摘要:在實(shí)際項(xiàng)目中,這么做肯定是不行的實(shí)際項(xiàng)目中不會(huì)使用內(nèi)存數(shù)據(jù)庫(kù),這種數(shù)據(jù)庫(kù)一般只是在單元測(cè)試中使用。接下來(lái),我們將會(huì)了解中單元測(cè)試的相關(guān)知識(shí)。
在上一篇文章,我們介紹了SQLAlchemy的基本概念,也介紹了基本的使用流程。本文我們結(jié)合webdemo這個(gè)項(xiàng)目來(lái)介紹如何在項(xiàng)目中使用SQLAlchemy。另外,我們還會(huì)介紹數(shù)據(jù)庫(kù)版本管理的概念和實(shí)踐,這也是OpenStack每個(gè)項(xiàng)目都需要做的事情。
Webdemo中的數(shù)據(jù)模型的定義和實(shí)現(xiàn)我們之前在webdemo項(xiàng)目中已經(jīng)開發(fā)了一個(gè)user管理的API,可以在這里回顧。當(dāng)時(shí)只是接收了API請(qǐng)求并且打印信息,并沒(méi)有實(shí)際的進(jìn)行數(shù)據(jù)存儲(chǔ)。現(xiàn)在我們就要引入數(shù)據(jù)庫(kù)操作,來(lái)完成user管理的API。
User數(shù)據(jù)模型在開發(fā)數(shù)據(jù)庫(kù)應(yīng)用前,需要先定義好數(shù)據(jù)模型。因?yàn)楸疚闹皇且菔維QLAlchemy的應(yīng)用,所以我們定義個(gè)最簡(jiǎn)單的數(shù)據(jù)模型。user表的定義如下:
id: 主鍵,一般由數(shù)據(jù)庫(kù)的自增類型實(shí)現(xiàn)。
user_id: user id,是一個(gè)UUID字符串,是OpenStack中最常用來(lái)標(biāo)記資源的方式,全局唯一,并且為該字段建立索引。
name: user的名稱,允許修改,全局唯一,不能為空。
email: user的email,允許修改,可以為空。
搭建數(shù)據(jù)庫(kù)層的代碼框架OpenStack項(xiàng)目中我見過(guò)兩種數(shù)據(jù)庫(kù)的代碼框架分隔,一種是Keystone的風(fēng)格,它把一組API的API代碼和數(shù)據(jù)庫(kù)代碼都放在同一個(gè)目錄下,如下所示:
采用Pecan框架的項(xiàng)目則大多把數(shù)據(jù)庫(kù)相關(guān)代碼都放在db目錄下,比如Magnum項(xiàng)目,如下所示:
由于webdemo采用的是Pecan框架,而且把數(shù)據(jù)庫(kù)操作的代碼放到同一個(gè)目錄下也會(huì)比較清晰,所以我們采用和Magnum項(xiàng)目相同的方式來(lái)編寫數(shù)據(jù)庫(kù)相關(guān)的代碼,創(chuàng)建webdemo/db目錄,然后把數(shù)據(jù)庫(kù)操作的相關(guān)代碼都放在這個(gè)目錄下,如下所示:
由于webdemo項(xiàng)目還沒(méi)有使用oslo_db庫(kù),所以代碼看起來(lái)比較直觀,沒(méi)有Magnum項(xiàng)目復(fù)雜。接下來(lái),我們就要開始寫數(shù)據(jù)庫(kù)操作的相關(guān)代碼,分為兩個(gè)步驟:
在db/models.py中定義User類,對(duì)應(yīng)數(shù)據(jù)庫(kù)的user表。
在db/api.py中實(shí)現(xiàn)一個(gè)Connection類,這個(gè)類封裝了所有的數(shù)據(jù)庫(kù)操作接口。我們會(huì)在這個(gè)類中實(shí)現(xiàn)對(duì)user表的CRUD等操作。
定義User數(shù)據(jù)模型映射類db/models.py中的代碼如下:
from sqlalchemy import Column, Integer, String from sqlalchemy.ext import declarative from sqlalchemy import Index Base = declarative.declarative_base() class User(Base): """User table""" __tablename__ = "user" __table_args__ = ( Index("ix_user_user_id", "user_id"), ) id = Column(Integer, primary_key=True) user_id = Column(String(255), nullable=False) name = Column(String(64), nullable=False, unique=True) email = Column(String(255))
我們按照我們之前定義的數(shù)據(jù)模型,實(shí)現(xiàn)了映射類。
實(shí)現(xiàn)DB API DB通用函數(shù)在db/api.py中,我們先定義了一些通用函數(shù),代碼如下:
from sqlalchemy import create_engine import sqlalchemy.orm from sqlalchemy.orm import exc from webdemo.db import models as db_models _ENGINE = None _SESSION_MAKER = None def get_engine(): global _ENGINE if _ENGINE is not None: return _ENGINE _ENGINE = create_engine("sqlite://") db_models.Base.metadata.create_all(_ENGINE) return _ENGINE def get_session_maker(engine): global _SESSION_MAKER if _SESSION_MAKER is not None: return _SESSION_MAKER _SESSION_MAKER = sqlalchemy.orm.sessionmaker(bind=engine) return _SESSION_MAKER def get_session(): engine = get_engine() maker = get_session_maker(engine) session = maker() return session
上面的代碼中,我們定義了三個(gè)函數(shù):
get_engine:返回全局唯一的engine,不需要重復(fù)分配。
get_session_maker:返回全局唯一的session maker,不需要重復(fù)分配。
get_session:每次返回一個(gè)新的session,因?yàn)橐粋€(gè)session不能同時(shí)被兩個(gè)數(shù)據(jù)庫(kù)客戶端使用。
這三個(gè)函數(shù)是使用SQLAlchemy中經(jīng)常會(huì)封裝的,所以O(shè)penStack的oslo_db項(xiàng)目就封裝了這些函數(shù),供所有的OpenStack項(xiàng)目使用。
這里需要注意一個(gè)地方,在get_engine()中:
_ENGINE = create_engine("sqlite://") db_models.Base.metadata.create_all(_ENGINE)
我們使用了sqlite內(nèi)存數(shù)據(jù)庫(kù),并且立刻創(chuàng)建了所有的表。這么做只是為了演示方便。在實(shí)際的項(xiàng)目中,create_engine()的數(shù)據(jù)庫(kù)URL參數(shù)應(yīng)該是從配置文件中讀取的,而且也不能在創(chuàng)建engine后就創(chuàng)建所有的表(這樣數(shù)據(jù)庫(kù)的數(shù)據(jù)都丟了)。要解決在數(shù)據(jù)庫(kù)中建表的問(wèn)題,就要先了解數(shù)據(jù)庫(kù)版本管理的知識(shí),也就是database migration,我們?cè)谙挛闹袝?huì)說(shuō)明。
Connection實(shí)現(xiàn)Connection的實(shí)現(xiàn)就簡(jiǎn)單得多了,直接看代碼。這里只實(shí)現(xiàn)了get_user()和list_users()方法。
class Connection(object): def __init__(self): pass def get_user(self, user_id): query = get_session().query(db_models.User).filter_by(user_id=user_id) try: user = query.one() except exc.NoResultFound: # TODO(developer): process this situation pass return user def list_users(self): session = get_session() query = session.query(db_models.User) users = query.all() return users def update_user(self, user): pass def delete_user(self, user): pass在API Controller中使用DB API
現(xiàn)在我們有了DB API,接下來(lái)就是要在Controller中使用它。對(duì)于使用Pecan框架的應(yīng)用來(lái)說(shuō),我們定義一個(gè)Pecan hook,這個(gè)hook在每個(gè)請(qǐng)求進(jìn)來(lái)的時(shí)候?qū)嵗粋€(gè)db的Connection對(duì)象,然后在controller代碼中我們可以直接使用這個(gè)Connection實(shí)例。關(guān)于Pecan hook的相關(guān)信息,請(qǐng)查看Pecan官方文檔。
首先,我們要實(shí)現(xiàn)這個(gè)hook,并且加入到app中。hook的實(shí)現(xiàn)代碼在webdemo/api/hooks.py中:
from pecan import hooks from webdemo.db import api as db_api class DBHook(hooks.PecanHook): """Create a db connection instance.""" def before(self, state): state.request.db_conn = db_api.Connection()
然后,修改webdemo/api/app.py中的setup_app()方法:
def setup_app(): config = get_pecan_config() app_hooks = [hooks.DBHook()] app_conf = dict(config.app) app = pecan.make_app( app_conf.pop("root"), logging=getattr(config, "logging", {}), hooks=app_hooks, **app_conf ) return app
現(xiàn)在,我們就可以在controller使用DB API了。我們這里要重新實(shí)現(xiàn)API服務(wù)(4)實(shí)現(xiàn)的GET /v1/users這個(gè)接口:
... class User(wtypes.Base): id = int user_id = wtypes.text name = wtypes.text email = wtypes.text class Users(wtypes.Base): users = [User] ... class UsersController(rest.RestController): @pecan.expose() def _lookup(self, user_id, *remainder): return UserController(user_id), remainder @expose.expose(Users) def get(self): db_conn = request.db_conn # 獲取DBHook中創(chuàng)建的Connection實(shí)例 users = db_conn.list_users() # 調(diào)用所需的DB API users_list = [] for user in users: u = User() u.id = user.id u.user_id = user.user_id u.name = user.name u.email = user.email users_list.append(u) return Users(users=users_list) @expose.expose(None, body=User, status_code=201) def post(self, user): print user
現(xiàn)在,我們就已經(jīng)完整的實(shí)現(xiàn)了這個(gè)API,客戶端訪問(wèn)API時(shí)是從數(shù)據(jù)庫(kù)拿數(shù)據(jù),而不是返回一個(gè)模擬的數(shù)據(jù)。讀者可以使用API服務(wù)(4)中的方法運(yùn)行測(cè)試服務(wù)器來(lái)測(cè)試這個(gè)API。注意:由于數(shù)據(jù)庫(kù)操作依賴于SQLAlchemy庫(kù),所以需要把它添加到requirement.txt中:SQLAlchemy<1.1.0,>=0.9.9。
小結(jié)現(xiàn)在我們已經(jīng)完成了數(shù)據(jù)庫(kù)層的代碼框架搭建,讀者可以大概了解到一個(gè)OpenStack項(xiàng)目中是如何進(jìn)行數(shù)據(jù)庫(kù)操作的。上面的代碼可以到https://github.com/diabloneo/webdemo下載。
數(shù)據(jù)庫(kù)版本管理 數(shù)據(jù)庫(kù)版本管理的概念上面我們?cè)?b>get_engine()函數(shù)中使用了內(nèi)存數(shù)據(jù)庫(kù),并且創(chuàng)建了所有的表。在實(shí)際項(xiàng)目中,這么做肯定是不行的:
實(shí)際項(xiàng)目中不會(huì)使用內(nèi)存數(shù)據(jù)庫(kù),這種數(shù)據(jù)庫(kù)一般只是在單元測(cè)試中使用。
如果每次create_engine都把數(shù)據(jù)庫(kù)的表重新創(chuàng)建一次,那么數(shù)據(jù)庫(kù)中的數(shù)據(jù)就丟失了,絕對(duì)不可容忍。
解決這個(gè)問(wèn)題的辦法也很簡(jiǎn)單:不使用內(nèi)存數(shù)據(jù)庫(kù),并且在運(yùn)行項(xiàng)目代碼前先把數(shù)據(jù)庫(kù)中的表都建好。這么做確實(shí)是解決了問(wèn)題,但是看起來(lái)有點(diǎn)麻煩:
如果每次都手動(dòng)寫SQL語(yǔ)句來(lái)創(chuàng)建數(shù)據(jù)庫(kù)中的表,會(huì)很容易出錯(cuò),而且很麻煩。
如果項(xiàng)目修改了數(shù)據(jù)模型,那么不能簡(jiǎn)單的修改建表的SQL語(yǔ)句,因?yàn)橹匦陆ū頃?huì)讓數(shù)據(jù)丟失。我們只能增加新的SQL語(yǔ)句來(lái)修改現(xiàn)有的數(shù)據(jù)庫(kù)。
最關(guān)鍵的是:我們?cè)趺粗酪粋€(gè)正在生產(chǎn)運(yùn)行的數(shù)據(jù)庫(kù)是要執(zhí)行那些SQL語(yǔ)句?如果數(shù)據(jù)庫(kù)第一次使用,那么執(zhí)行全部的語(yǔ)句是正確的;如果數(shù)據(jù)庫(kù)已經(jīng)在使用,里面有數(shù)據(jù),那么我們只能執(zhí)行那些修改表定義的SQL語(yǔ)句,而不能執(zhí)行那些重新建表的SQL語(yǔ)句。
為了解決這種問(wèn)題,就有人發(fā)明了數(shù)據(jù)庫(kù)版本管理的概念,也稱為Database Migration。基本原理是:在我們要使用的數(shù)據(jù)庫(kù)中建立一張表,里面保存了數(shù)據(jù)庫(kù)的當(dāng)前版本,然后我們?cè)诖a中為每個(gè)數(shù)據(jù)庫(kù)版本寫好所需的SQL語(yǔ)句。當(dāng)對(duì)一個(gè)數(shù)據(jù)庫(kù)執(zhí)行migration操作時(shí),會(huì)執(zhí)行從當(dāng)前版本到目標(biāo)版本之間的所有SQL語(yǔ)句。舉個(gè)例子:
在Version 1時(shí),我們?cè)跀?shù)據(jù)庫(kù)中建立一個(gè)user表。
在Version 2時(shí),我們?cè)跀?shù)據(jù)庫(kù)中建立一個(gè)project表。
在Version 3時(shí),我們修改user表,增加一個(gè)age列。
那么在我們對(duì)一個(gè)數(shù)據(jù)庫(kù)執(zhí)行migration操作,數(shù)據(jù)庫(kù)的當(dāng)前版本Version 1,我們?cè)O(shè)定的目標(biāo)版本是Version 3,那么操作就是:建立一個(gè)project表,修改user表,增加一個(gè)age列,并且把數(shù)據(jù)庫(kù)當(dāng)前版本設(shè)置為Version 3。
數(shù)據(jù)庫(kù)的版本管理是所有大型數(shù)據(jù)庫(kù)項(xiàng)目的需求,每種語(yǔ)言都有自己的解決方案。OpenStack中主要使用SQLAlchemy的兩種解決方案:sqlalchemy-migrate和Alembic。早期的OpenStack項(xiàng)目使用了sqlalchemy-migrate,后來(lái)?yè)Q成了Alembic。做出這個(gè)切換的主要原因是Alembic對(duì)數(shù)據(jù)庫(kù)版本的設(shè)計(jì)和管理更靈活,可以支持分支,而sqlalchemy-migrate只能支持直線的版本管理,具體可以看OpenStack的WiKi文檔Alembic。
接下來(lái),我們就在我們的webdemo項(xiàng)目中引入Alembic來(lái)進(jìn)行版本管理。
Alembic要使用Alembic,大概需要以下步驟:
安裝Alembic
在項(xiàng)目中創(chuàng)建Alembic的migration環(huán)境
修改Alembic配置文件
創(chuàng)建migration腳本
執(zhí)行遷移動(dòng)作
看起來(lái)步驟很復(fù)雜,其實(shí)搭建好環(huán)境后,新增數(shù)據(jù)庫(kù)版本只需要執(zhí)行最后兩個(gè)步驟。
安裝Alembic在webdemo/requirements.txt中加入:alembic>=0.8.0。然后在virtualenv中安裝即可。
在項(xiàng)目中創(chuàng)建Alembic的migration環(huán)境一般OpenStack項(xiàng)目中,Alembic的環(huán)境都是放在db/sqlalchemy/目錄下,因此,我們先建立目錄webdemo/db/sqlalchemy/,然后在這個(gè)目錄下初始化Alembic環(huán)境:
(.venv)? ~/programming/python/webdemo git:(master) ? $ cd webdemo/db (.venv)? ~/programming/python/webdemo/webdemo/db git:(master) ? $ ls api.py api.pyc __init__.py __init__.pyc models.py models.pyc sqlalchemy (.venv)? ~/programming/python/webdemo/webdemo/db git:(master) ? $ cd sqlalchemy (.venv)? ~/programming/python/webdemo/webdemo/db/sqlalchemy git:(master) ? $ ls (.venv)? ~/programming/python/webdemo/webdemo/db/sqlalchemy git:(master) ? $ alembic init alembic Creating directory /home/diabloneo/programming/python/webdemo/webdemo/db/sqlalchemy/alembic ... done Creating directory /home/diabloneo/programming/python/webdemo/webdemo/db/sqlalchemy/alembic/versions ... done Generating /home/diabloneo/programming/python/webdemo/webdemo/db/sqlalchemy/alembic/script.py.mako ... done Generating /home/diabloneo/programming/python/webdemo/webdemo/db/sqlalchemy/alembic.ini ... done Generating /home/diabloneo/programming/python/webdemo/webdemo/db/sqlalchemy/alembic/README ... done Generating /home/diabloneo/programming/python/webdemo/webdemo/db/sqlalchemy/alembic/env.pyc ... done Generating /home/diabloneo/programming/python/webdemo/webdemo/db/sqlalchemy/alembic/env.py ... done Please edit configuration/connection/logging settings in "/home/diabloneo/programming/python/webdemo/webdemo/db/sqlalchemy/alembic.ini" before proceeding. (.venv)? ~/programming/python/webdemo/webdemo/db/sqlalchemy git:(master) ? $
現(xiàn)在,我們就在webdemo/db/sqlalchemy/alembic/目錄下建立了一個(gè)Alembic migration環(huán)境:
修改Alembic配置文件webdemo/db/sqlalchemy/alembic.ini文件是Alembic的配置文件,我們現(xiàn)在需要修改文件中的sqlalchemy.url這個(gè)配置項(xiàng),用來(lái)指向我們的數(shù)據(jù)庫(kù)。這里,我們使用SQLite數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)文件存放在webdemo項(xiàng)目的根目錄下,名稱是webdemo.db:
# sqlalchemy.url = driver://user:pass@localhost/dbname sqlalchemy.url = sqlite:///../../../webdemo.db
注意:實(shí)際項(xiàng)目中,數(shù)據(jù)庫(kù)的URL信息是從項(xiàng)目配置文件中讀取,然后通過(guò)動(dòng)態(tài)的方式傳遞給Alembic的。具體的做法,讀者可以參考Magnum項(xiàng)目的實(shí)現(xiàn):https://github.com/openstack/magnum/blob/master/magnum/db/sqlalchemy/migration.py。
創(chuàng)建migration腳本現(xiàn)在,我們可以創(chuàng)建第一個(gè)遷移腳本了,我們的第一個(gè)數(shù)據(jù)庫(kù)版本就是創(chuàng)建我們的user表:
(.venv)? ~/programming/python/webdemo/webdemo/db/sqlalchemy git:(master) ? $ alembic revision -m "Create user table" Generating /home/diabloneo/programming/python/webdemo/webdemo/db/sqlalchemy/alembic/versions/4bafdb464737_create_user_table.py ... done
現(xiàn)在腳本已經(jīng)幫我們生成好了,不過(guò)這個(gè)只是一個(gè)空的腳本,我們需要自己實(shí)現(xiàn)里面的具體操作,補(bǔ)充完整后的腳本如下:
"""Create user table Revision ID: 4bafdb464737 Revises: Create Date: 2016-02-21 12:24:46.640894 """ # revision identifiers, used by Alembic. revision = "4bafdb464737" down_revision = None branch_labels = None depends_on = None from alembic import op import sqlalchemy as sa def upgrade(): op.create_table( "user", sa.Column("id", sa.Integer, primary_key=True), sa.Column("user_id", sa.String(255), nullable=False), sa.Column("name", sa.String(64), nullable=False, unique=True), sa.Column("email", sa.String(255)) ) def downgrade(): op.drop_table("user")
其實(shí)就是把User類的定義再寫了一遍,使用了Alembic提供的接口來(lái)方便的創(chuàng)建和刪除表。
執(zhí)行遷移操作我們需要在webdemo/db/sqlalchemy/目錄下執(zhí)行遷移操作,可能需要手動(dòng)指定PYTHONPATH:
(.venv)? ~/programming/python/webdemo/webdemo/db/sqlalchemy git:(master) ? $ PYTHONPATH=../../../ alembic upgrade head INFO [alembic.migration] Context impl SQLiteImpl. INFO [alembic.migration] Will assume non-transactional DDL. INFO [alembic.migration] Running upgrade -> 4bafdb464737, Create user table
alembic upgrade head會(huì)把數(shù)據(jù)庫(kù)升級(jí)到最新的版本。這個(gè)時(shí)候,在webdemo的根目錄下會(huì)出現(xiàn)webdemo.db這個(gè)文件,可以使用sqlite3命令查看內(nèi)容:
(.venv)? ~/programming/python/webdemo git:(master) ? $ ls AUTHORS build ChangeLog dist LICENSE README.md requirements.txt Session.vim setup.cfg setup.py webdemo webdemo.db webdemo.egg-info (.venv)? ~/programming/python/webdemo git:(master) ? $ sqlite3 webdemo.db SQLite version 3.8.11.1 2015-07-29 20:00:57 Enter ".help" for usage hints. sqlite> .tables alembic_version user sqlite> .schema alembic_version CREATE TABLE alembic_version ( version_num VARCHAR(32) NOT NULL ); sqlite> .schema user CREATE TABLE user ( id INTEGER NOT NULL, user_id VARCHAR(255) NOT NULL, name VARCHAR(64) NOT NULL, email VARCHAR(255), PRIMARY KEY (id), UNIQUE (name) ); sqlite> .header on sqlite> select * from alembic_version; version_num 4bafdb464737測(cè)試新的數(shù)據(jù)庫(kù)
現(xiàn)在我們可以把之前使用的內(nèi)存數(shù)據(jù)庫(kù)換掉,使用我們的文件數(shù)據(jù)庫(kù),修改get_engine()函數(shù):
def get_engine(): global _ENGINE if _ENGINE is not None: return _ENGINE _ENGINE = create_engine("sqlite:///webdemo.db") return _ENGINE
現(xiàn)在你可以手動(dòng)往webdemo.db中添加數(shù)據(jù),然后測(cè)試下API:
? ~/programming/python/webdemo git:(master) ? $ sqlite3 webdemo.db SQLite version 3.8.11.1 2015-07-29 20:00:57 Enter ".help" for usage hints. sqlite> .header on sqlite> select * from user; sqlite> .schema user CREATE TABLE user ( id INTEGER NOT NULL, user_id VARCHAR(255) NOT NULL, name VARCHAR(64) NOT NULL, email VARCHAR(255), PRIMARY KEY (id), UNIQUE (name) ); sqlite> insert into user values(1, "user_id", "Alice", "alice@example.com"); sqlite> select * from user; id|user_id|name|email 1|user_id|Alice|alice@example.com sqlite> .q ? ~/programming/python/webdemo git:(master) ? $ ? ~/programming/python/webdemo git:(master) ? $ curl http://localhost:8080/v1/users {"users": [{"email": "alice@example.com", "user_id": "user_id", "id": 1, "name": "Alice"}]}%小結(jié)
現(xiàn)在,我們就已經(jīng)完成了database migration代碼框架的搭建,可以成功執(zhí)行了第一個(gè)版本的數(shù)據(jù)庫(kù)遷移。OpenStack項(xiàng)目中也是這么來(lái)做數(shù)據(jù)庫(kù)遷移的。后續(xù),一旦修改了項(xiàng)目,需要修改數(shù)據(jù)模型時(shí),只要新增migration腳本即可。這部分代碼也可以在https://github.com/diabloneo/webdemo中看到。
在實(shí)際生產(chǎn)環(huán)境中,當(dāng)我們發(fā)布了一個(gè)項(xiàng)目的新版本后,在上線的時(shí)候,都會(huì)自動(dòng)執(zhí)行數(shù)據(jù)庫(kù)遷移操作,升級(jí)數(shù)據(jù)庫(kù)版本到最新的版本。如果線上的數(shù)據(jù)庫(kù)版本已經(jīng)是最新的,那么這個(gè)操作沒(méi)有任何影響;如果不是最新的,那么會(huì)把數(shù)據(jù)庫(kù)升級(jí)到最新的版本。
關(guān)于Alembic的更多使用方法,請(qǐng)閱讀官方文檔Alembic。
總結(jié)本文到這邊就結(jié)束了,這兩篇文章我們了解OpenStack中數(shù)據(jù)庫(kù)應(yīng)用開發(fā)的基礎(chǔ)知識(shí)。接下來(lái),我們將會(huì)了解OpenStack中單元測(cè)試的相關(guān)知識(shí)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/37772.html
摘要:通過(guò),也就是通過(guò)各個(gè)項(xiàng)目提供的來(lái)使用各個(gè)服務(wù)的功能。通過(guò)使用的方式是由各個(gè)服務(wù)自己實(shí)現(xiàn)的,比如負(fù)責(zé)計(jì)算的項(xiàng)目實(shí)現(xiàn)了計(jì)算相關(guān)的,負(fù)責(zé)認(rèn)證的項(xiàng)目實(shí)現(xiàn)了認(rèn)證和授權(quán)相關(guān)的。的服務(wù)都是使用的方式來(lái)部署的。 使用OpenStack服務(wù)的方式 OpenStack項(xiàng)目作為一個(gè)IaaS平臺(tái),提供了三種使用方式: 通過(guò)Web界面,也就是通過(guò)Dashboard(面板)來(lái)使用平臺(tái)上的功能。 通過(guò)命令行,也就...
摘要:本文將進(jìn)入單元測(cè)試的部分,這也是基礎(chǔ)知識(shí)中最后一個(gè)大塊。本文將重點(diǎn)講述和中的單元測(cè)試的生態(tài)環(huán)境。另外,在中指定要運(yùn)行的單元測(cè)試用例的完整語(yǔ)法是。中使用模塊管理單元測(cè)試用例。每個(gè)項(xiàng)目的單元測(cè)試代碼結(jié)構(gòu)可 本文將進(jìn)入單元測(cè)試的部分,這也是基礎(chǔ)知識(shí)中最后一個(gè)大塊。本文將重點(diǎn)講述Python和OpenStack中的單元測(cè)試的生態(tài)環(huán)境。 單元測(cè)試的重要性 github上有個(gè)人畫了一些不同語(yǔ)言的學(xué)...
摘要:不幸的是,在軟件包管理十分混亂,至少歷史上十分混亂。的最大改進(jìn)是將函數(shù)的參數(shù)單獨(dú)放到一個(gè)的文件中這些成為包的元數(shù)據(jù)?;诘陌姹咎?hào)管理。的版本推導(dǎo)這里重點(diǎn)說(shuō)明一下基于的版本號(hào)管理這個(gè)功能。開發(fā)版本號(hào)的形式如下。 為什么寫這個(gè)系列 OpenStack是目前我所知的最大最復(fù)雜的基于Python項(xiàng)目。整個(gè)OpenStack項(xiàng)目包含了數(shù)十個(gè)主要的子項(xiàng)目,每個(gè)子項(xiàng)目所用到的庫(kù)也不盡相同。因此,對(duì)于...
摘要:另外,項(xiàng)目在單元測(cè)試中使用的是的內(nèi)存數(shù)據(jù)庫(kù),這樣開發(fā)者運(yùn)行單元測(cè)試的時(shí)候不需要安裝和配置復(fù)雜的數(shù)據(jù)庫(kù),只要安裝好就可以了。而且,數(shù)據(jù)庫(kù)是保存在內(nèi)存中的,會(huì)提高單元測(cè)試的速度。是實(shí)現(xiàn)層的基礎(chǔ)。項(xiàng)目一般會(huì)使用數(shù)據(jù)庫(kù)來(lái)運(yùn)行單元測(cè)試。 OpenStack中的關(guān)系型數(shù)據(jù)庫(kù)應(yīng)用 OpenStack中的數(shù)據(jù)庫(kù)應(yīng)用主要是關(guān)系型數(shù)據(jù)庫(kù),主要使用的是MySQL數(shù)據(jù)庫(kù)。當(dāng)然也有一些NoSQL的應(yīng)用,比如Ce...
摘要:到這里,我們的服務(wù)的框架已經(jīng)搭建完成,并且測(cè)試服務(wù)器也跑起來(lái)了。上面的代碼也就可以修改為再次運(yùn)行我們的測(cè)試服務(wù)器,就可以返現(xiàn)返回值為格式了。我們先來(lái)完成利用來(lái)檢查返回值的代碼方法的第一個(gè)參數(shù)表示返回值的類型這樣就完成了的返回值檢查了。 上一篇文章說(shuō)到,我們將以實(shí)例的形式來(lái)繼續(xù)講述這個(gè)API服務(wù)的開發(fā)知識(shí),這里會(huì)使用Pecan和WSME兩個(gè)庫(kù)。 設(shè)計(jì)REST API 要開發(fā)REST AP...
閱讀 1648·2021-10-14 09:42
閱讀 3915·2021-09-07 09:59
閱讀 1368·2019-08-30 15:55
閱讀 639·2019-08-30 11:17
閱讀 3400·2019-08-29 16:06
閱讀 569·2019-08-29 14:06
閱讀 3197·2019-08-28 18:14
閱讀 3718·2019-08-26 13:55