zoukankan      html  css  js  c++  java
  • Openstack 通过 SQLAlchemy-ORM 访问数据库

    目录

    Demo

    Github/JmilkFan/my-code-repertory/openstack

    SQLAlchemy

    SQLAlchemy 是 Python 下的一款开源软件。提供了 SQL对象关系映射(ORM/Object Relational Mappers)工具。使开发者可以像操作对象一般的操作数据库。

    SQLAlchemy 1.1 Documentation
    SQLAlchemy 1.0 Documentation

    数据库的初始化

    在部署 Openstack Services 的过程中需要为这些 Services 创建数据库 :

    CREATE DATABASE glance;

    这时我们其实仅仅是建立了数据库而已, 但是数据库中并没有表结构, 所以 Openstack Services 还提供了一条初始化(同步)数据库的指令 :

    glance-manage db_sync

    下面是 db_sync的代码实现方式:

    # octopunch/octopunch/db/sqlalchemy/migrate_repo/versions/001_octopunch_init.py
    def define_tables(meta):
        vcenters = Table(
            'vcenters', meta,
            Column('created_at', DateTime),
            Column('updated_at', DateTime),
            Column('deleted_at', DateTime),
            Column('uuid', String(length=45), primary_key=True),
            Column('vc_value', String(length=255)),
            Column('name', String(length=255)),
            Column('vcs_ip', String(length=255), nullable=False),
            Column('username', String(length=255), nullable=False),
            Column('password', String(length=255), nullable=False),
            mysql_engine='InnoDB'
        )

    这些 Table 的定义就是我们数据库表结构的定义, 它会在我们执行数据库初始化指令的时候被用于表的创建.

    数据库的操作实现

    Openstack Services 对数据库的操作一般就是对数据库中的资源表的操作, 也就是对资源的操作, 所以我们先看看 Openstack 中的资源是怎么定义的.

    octopunch/octopunch/api/v1/router.py
    mapper.connect() 将Resource URL & Action方法 & Controller & HTTP函数 绑定到一起, 实现HTTP请求/资源/操作函数的一一对应.

    from octopunch.api.v1 import vcenter
    
    
    class APIRouter(octopunch.api.openstack.APIRouter):
    
    ...
    
        def _setup_routes(self, mapper, ext_mgr):
            self.resources['versions'] = versions.create_resource()
            mapper.connect("versions", "/",
                           controller=self.resources['versions'],
                           action='show')
    
            mapper.redirect("", "/")
    
            self.resources['vcenters'] = vcenter.create_resource(ext_mgr)
            mapper.resource('vcenter', 'vcenters',
                             controller=self.resources['vcenters'])
    

    octopunch/octopunch/api/v1/vcenter.py
    每一个 Resource 都会对应有一个 Controller 的类定义, 包含了对应的 Action 方法的实现.

    class VcenterController(wsgi.Controller):
    ...
        def index(self, req):
            """Show all vcenter list."""
            context = req.environ['octopunch.context']
            vcenters = self.vcenter_api.vcenter_list(context)
            return {'vcenters':vcenters}
    ...
    def create_resource(ext_mgr):
        """Vcenter resource factory method."""
        return wsgi.Resource(VcenterController(ext_mgr))

    octopunch/octopunch/vsphere/vcenter/api.py
    在 Resource 目录下的 api.py 文件中定义对数据库的操作接口.

    from octopunch.db import base
    
    class API(base.Base):
    
        def vcenter_list(self, context, filters=None):
            """Get vcenter list.
    
            :param context: class:`RequestContext` instance
    
            :param filters: select data by filter.
            :type: ``dict``
    
            :return: return a list of class:`VenterInfo` instance
            """
            return self.db.vcenter_get_all(context, filters)

    octopunch/octopunch/db/api.py
    这一层 API 接口决定使用哪种 ORM 实现和数据库类型, 而且还定义了对应 vcenter/api.py 中数据库操作接口的函数. 这样做是为了支持 Openstack 数据库的异构性. 首先需要在 octopunch/octopunch/db/base.py 中使用self.db.dispose_engine()方法让 Openstack 与数据库建立连接.

    # octopunch/octopunch/db/base.py
    class Base(object):
        """DB driver is injected in the init method."""
    
        def __init__(self, db_driver=None):
            # NOTE(mriedem): Without this call, multiple inheritance involving
            # the db Base class does not work correctly.
            super(Base, self).__init__()
            if not db_driver:
                db_driver = CONF.db_driver
            self.db = importutils.import_module(db_driver)  # pylint: disable=C0103
            self.db.dispose_engine()
    
    # octopunch/octopunch/db/api.py
    from oslo_db import concurrency as db_concurrency
    ...
    
    # 指定使用 SQLALchemy, 并指定了 SQLAlchhemy 的接口路径
    _BACKEND_MAPPING = {'sqlalchemy': 'octopunch.db.sqlalchemy.api'}
    IMPL = db_concurrency.TpoolDbapiWrapper(CONF, _BACKEND_MAPPING)
    
    
    ...
    def vcenter_get_all(context, filters=None):
        """Get the vcenter list.
    
        :param context: class:`RequestContext` instance
    
        :param filters: select data by filters.
        :type: ``dict``
    
        :return: return a list of class:`VcenterInfo` instance.
        """
        return IMPL.vcenter_get_all(context, filters=filters)

    octopunch/octopunch/db/sqlalchemy/api.py
    这里是 SQLAlchemy 操作数据库的具体实现, EG: 查询

    @require_context
    def vcenter_get_all(context, filters=None):
        session = get_session()
        with session.begin():
            vcenters_info = session.query(models.Vcenter).all()
        return vcenters_info

    ORM 的数据库操作方式中, 很重要一部分就是 Table Mapping Class 的实现:

    # octopunch/octopunch/db/sqlalchemy/models.py
    class Vcenter(BASE, OctopunchBase):
        """Represents the vcenter list."""
    
        __tablename__ = 'vcenters'
        vc_value = Column(String(255))
        name = Column(String(255))
        vcs_ip = Column(String(255), nullable=False)
        username = Column(String(255), nullable=False)
        password = Column(String(255), nullable=False)
    
        datacenters = relationship('Datacenter', backref='vcenters',
                                   foreign_keys='Datacenter.vcenter_uuid',
                                   primaryjoin='Vcenter.uuid =='
                                               'Datacenter.vcenter_uuid')
    

    将上述的 Table 定义映射为 Class之后, 我们就可以通过对 Class instance 的操作来实现对数据库 Table 的操作.

    数据库的操作请求

    在调试的时候我们可以在客户端通过 curl 指令来发送 HTTP 请求, 一般来说对每个 Resource 的 HTTP 请求都具有下面 5 种类型, 每一种类型都应该在 api/v1/resourceName.py 文件下(针对本文而言, 其实可以有多种实现方式)有相应的 Action 实现函数, 当然我们还可以自定义更多的实现方法.

    全部查询

    GET <==> show

    curl-i 'http://<Service_host_ip>:<service_port>/v1/<project_id>/<ResourceUrl>' -X GET -H "Acceptn" -H "X: admin" -H "X-Auth-Token: <token_id>"

    单个查询

    GET <==> index

    curl-i 'http://<Service_host_ip>:<service_port>/v1/<project_id>/<ResourceUrl>/<ResourceID>' -X GET -H "Acceptn" -H "X-Auth-Project-Id: admin" -H "X-Auth-Token: <token_id>"

    创建

    POST <==> create

    curl-i 'http://<Service_host_ip>:<service_port>/v1/<project_id>/<ResourceUrl>' -X POST -H "Content-Type: application/json" -H "X-Auth-Project-Id: admin" -H "X-Auth-Token: <token_id>" -d '<body_content_dict>'

    更新

    PUT <==> update

    curl-i 'http://<Service_host_ip>:<service_port>/v1/<project_id>/<ResourceUrl>/<ResourceID>' -X PUT -H "Content-Type: application/json" -H "X-Auth-Project-Id: admin" -H "X-Auth-Token: <token_id>" -d '<body_content_dict>'

    删除

    DELETE <==> delete

    curl-i 'http://<Service_host_ip>:<service_port>/v1/<project_id>/<ResourceUrl>/<ResourceID>' -X DELETE -H "Acceptn" -H "X-Auth-Project-Id: admin" -H "X-Auth-Token: <token_id>"

    相关阅读:

  • 相关阅读:
    【javascript】select操作实例
    【javascript】函数
    【javascript】一些资料
    【javascript】操作符:一元操作符
    动态执行Sql
    索引( index )
    事务
    用户相关
    视图(view)
    函数(function)
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13310750.html
Copyright © 2011-2022 走看看