学习 OpenStack (4):基于 Pecan 开发 OpenStack 组件(Demo) _____2


前言

内容主要用作个人学习总结,如有描述错误,欢迎指明

进入正题之前建议先通过 pecan 框架实现一个 "hello world" ,Pecan: quick_start
这篇随笔将构建整合&验证API

目录结构

第 1 层

$ tree -L 1
.
|-- README.md
|-- etc             # 存放本地配置文件,例如 *.conf、api_paste.ini 等
|-- libs            # 环境构建过程较难安装的依赖包 *.whl
|-- log             # 存放本地调试的日志
|-- pecan_demo      # 项目
|-- setup.cfg       # 安装: 声明式 配置文件
`-- setup.py        # 安装: python 执行脚本

4 directories, 3 files

第 2 层


|-- pecan_demo
|   |-- __init__.py
|   |-- __init__.pyc
|   |-- api                 # API 核心
|   |-- cli                 # 预留的 Linux command
|   |-- common              # 公共模块
|   |-- config.py           # 预留配置文件,供 cfg 使用
|   |-- config.pyc
|   |-- db                  # 存储模块
|   |-- messaging.py        # 消息队列相关函数处理及封装
|   |-- messaging.pyc
|   |-- service.py          # cfg 加载&初始化
|   |-- service.pyc
|   |-- version.py          # 项目版本信息(pbr.version_info)
|   `-- version.pyc




内部实现

接下来按加载顺序依次介绍

#1 定义启动文件

debug用

文件:pecan_demo/api/run.py

from wsgiref import simple_server
from pecan_demo.api import app
# import pdb
# pdb.set_trace()
application = app.build_wsgi_app(argv=[])

# print(type(application))


if __name__ == '__main__':
    serve = simple_server.make_server('0.0.0.0', 8887, application)
    serve.serve_forever()

#2 配置 cfg

文件:etc/oslo-config-generator/dev/pecan_demo.conf

[DEFAULT]
api_paste_config = 'F:\***\pecan_demo\etc\pecan_test_api\api_paste.ini'
log_dir = F:\***\pecan_demo\log
auth_strategy = keystone

[database]
connection = mysql+pymysql://root:123456@localhost/pecan_demo

文件:pecan_demo/api/app.py

auth_opts = [
    cfg.StrOpt('api_paste_config',
               default="api_paste.ini",
               help="Configuration file for WSGI definition of API."),
    cfg.StrOpt('auth_strategy',
               choices=['noauth', 'keystone'],
               default='keystone',
               help=("The strategy to use for auth. Supports noauth and "
                     "keystone")),
]

# CONF.register_opts(auth_opts, group='DEFAULT')
CONF.register_opts(auth_opts)

所有 *.conf 里的配置项,都要在项目初始化时,在 cfg 里注册;oslo.config 相关的介绍网上太多了,不赘述 贴两个参考 、

#3 加载 cfg

文件:pecan_demo/service.py

def prepare_service(argv=None, config_files=None):
    if argv is None:
        argv = sys.argv                 # 命令行参数预留

    oslo_i18n.enable_lazy()             # 国际化模块
    log.register_options(cfg.CONF)      # 日志配置加载
    log.set_defaults()
    defaults.set_cors_middleware_defaults()

    # 配置解析(建议用 rpdb 断点调试这里,可以加深 oslo.config 模块的理解)
    cfg.CONF(argv[1:], project='pecan_demo', validate_default_values=True,
             version=version.version_info.version_string(),
             default_config_files=config_files)

    log.setup(cfg.CONF, 'pecan_demo')
    messaging.setup()
    return cfg.CONF

#4 Pecan 初始化

文件:pecan_demo/api/app.py

from pecan_demo.api import config as api_config
from pecan_demo.api import hooks

def get_pecan_config():
    # Set up the pecan configuration
    filename = api_config.__file__.replace('.pyc', '.py')   # api/config.py
    return pecan.configuration.conf_from_file(filename)

def setup_app(pecan_config=None, extra_hooks=None):

    app_conf = get_pecan_config()

    app_hooks = [
        hooks.ContextHook(),    # Pecan钩子,程序有预加载的数据或驱动,可以放在这里
    ]

    app = pecan.make_app(
        app_conf.app.root,      # 视图的根节点
        static_root=app_conf.app.static_root,
        template_path=app_conf.app.template_path,
        debug=CONF.api.pecan_debug,
        force_canonical=getattr(app_conf.app, 'force_canonical', True),
        hooks=app_hooks,
        guess_content_type_from_ext=False
    )

    return app      # wsgi application

文件:pecan_demo/api/config.py

# Pecan Application Configurations
app = {
    'root': 'pecan_demo.api.root.RootController',    # 视图根节点
    'modules': ['pecan_demo.api'],
    'static_root': '%(confdir)s/public',
    'template_path': '%(confdir)s/templates',
    'debug': False,
    'enable_acl': True,
    'acl_public_routes': ['/', '/v1'],
}

#5 视图&路由

Pecan 路由规则

视图结构

|-- api
|   |-- __init__.py
|   |-- __init__.pyc
|   |-- app.py
|   |-- app.pyc
|   |-- config.py
|   |-- config.pyc
|   |-- hooks.py
|   |-- hooks.pyc
|   |-- middleware.py
|   |-- root.py      # RootController
|   |-- root.pyc
|   |-- run.py
|   `-- v1           # API 版本控制,便于切换  .../v1/...  or  .../v2/...
|       |-- __init__.py
|       |-- __init__.pyc
|       |-- controllers     # 业务代码
|       |   |-- __init__.py # 集成各个模块的控制器
|       |   |-- __init__.pyc
|       |   |-- demo.py     # 按功能或业务划分控制器,例如:demo
|       |   `-- demo.pyc
|       `-- datamodels      # 对应存放各模块控制器,出入参的 schema
|           `-- __init__.py

文件:pecan_demo/api/root.py

from pecan_demo.api.v1 import controllers as v1_api

class RootController(rest.RestController):
    """Root REST Controller exposing versions of the API.

    """

    v1 = v1_api.V1Controller()      # root 控制器

    @wsme_pecan.wsexpose([APIVersion])
    def index(self):
        ...

文件:pecan_demo/api/v1/controllers/init.py

from pecan import rest

from pecan_demo.api.v1.controllers import demo as demo_api


class V1Controller(rest.RestController):
    """API version 1 controller.

    """

    demo = demo_api.DemoController()

文件:pecan_demo/api/v1/controllers/demo.py

import pecan
from pecan import rest


class DemoController(rest.RestController):

    @pecan.expose()
    def index(self):
        return 'DemoController'

#6 IDE 调试

...

铺垫基本完成了,剩下的要将代码放到 Linux 系统中调试,对接 OpenStack 组件的 API