• 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>"
  • 相关阅读:
    LeetCode Best Time to Buy and Sell Stock
    LeetCode Scramble String
    LeetCode Search in Rotated Sorted Array II
    LeetCode Gas Station
    LeetCode Insertion Sort List
    LeetCode Maximal Rectangle
    Oracle procedure
    浏览器下载代码
    Shell check IP
    KVM- 存储池配置
  • 原文地址:https://www.cnblogs.com/jmilkfan-fanguiju/p/7532312.html
Copyright © 2020-2023  润新知