Openstack基础组件概览(1)

熟悉Openstack的童鞋都清楚:Openstack下的大多数项目比如Nova、Keystone、Cinder、Glance、Neutron、Ceilometer等这些项目在开发时都会用到一个叫做oslo的基础公共库,如下就一些最常见的Openstack基础共用库简单展开聊聊他们各自的用途和基本用法。

1. oslo.config

该组件功能为Openstack解析配置文件,使用起来也比较容易,如下举一个简单的例子:

from oslo_config import cfg

CONF = cfg.CONF

options = [
  cfg.BoolOpt('source_is_ipv6',
                default=False,
                help='Source is ipv6'),
  cfg.StrOpt('cert',
               default='self.pem',
               help='SSL certificate file'),
]

CONF.register_opts(options)  # 默认放在default组下面,如果是其他组的配置,则可以使用CONF.register_opts(options, group=group)

# 然后就可以直接操作对应的配置参数,比如:
def test_func():
  print(CONF.cert)

Openstack配置文件使用INI文件格式,具体配置都会以键值对的形式呈现,并且可以分配到不同的group(默认是DEFAULT)下面,另外#开始的行是注释说明,针对上面的配置具体到文件里应该是如下样式:

[DEFAULT]
# Source is ipv6
# (boolean value)
source_is_ipv6 = True

# SSL certificate file
# (string value)
# cert = self.pem

对于设置了默认值的参数项,如果配置文件中没有配置则实际取默认值;参数项支持多种参数类型比如布尔型(BoolOpt)、字符串型(StrOpt)、浮点型(FloatOpt)、字典(DictOpt)、列表(ListOpt)、整型(IntOpt)、IP类型(IPOpt)、多值类型(MultiStrOpt)等;实际配置中可以对前面已经定义的参数项进行引用,具体方式跟bash引用变量类似,在key前加上$即可,而如果$有实际意义则用$$;另外如果实际的参数值包含空格,则需要把整个字符串值放在引号里。

使用

实际使用中,Openstack很多服务都需要基于配置文件来启动,只需在服务启动的命令后加上--config-file 即可。

oslo-config-generator

oslo-config-generator能够生成一个完整的配置文件的样本(默认格式是INI),实际使用时只需根据实际场景对这个配置文件更新即可,但在使用这个工具生成配置之前,需要定义配置的发现入口:

# 1. 设置setup.cfg
[entry_points]
oslo.config.opts = 
  oslo.messaging = oslo.messaging.opts:list_opts
  umha.conf = umha.opts.list_opts

# 2. 增加opts.py文件定义list_opts函数,比如增加umha/opts.py:
def list_opts():
  return [
        ('DEFAULT', utils.cfg.common_opts),
        ('time', utils.cfg.time_opts),
        ('db', [utils.cfg.db_opt]),
        ('auth', utils.cfg.auth_opts),
        ('email', utils.cfg.email_opts),
        ('valve', utils.cfg.valve_opts),
    ]

如此就可以通过命令:
oslo-config-generator --namespace umha.conf --namespace oslo.messaging > /etc/umha/umha.conf
生成所需的配置文件样本了。

2. oslo.cache

该组件为Openstack提供缓存功能,把一些常用的数据比如keystone token信息等放进缓存,降低数据库的压力提高查询效率。oslo.cache是通过dogpile.cache库为Openstack各个服务组件提供一个适用多种缓存后端的缓存接口,目前已经实现多种缓存后端的缓存设计比如Memcache、etcd、MongoDB等,其中Memcache最常用,因此本文仅就Nova项目(其他项目使用都类似)中的Memcache使用做展开。

Nova项目跟缓存相关的最核心的文件:./nova/cache_utils.py
这个文件主要实现了两大块:

  • 类CacheClient:定义缓存的各种操作比如查增删等;
  • 函数get_client():用来获取缓存client,其实质是类CacheClient的实例化,而实现的方式通常是基于oslo.config的配置来创建和配置region(dogpile.cache.region.CacheRegion类实例),之后基于这个region来生成一个CacheClient实例;

类CacheClient实现代码:

class CacheClient(object):
    def __init__(self, region):
        self.region = region

    def get(self, key):
        value = self.region.get(key)
        if value == cache.NO_VALUE:
            return None
        return value

    def get_or_create(self, key, creator):
        return self.region.get_or_create(key, creator)

    def set(self, key, value):
        return self.region.set(key, value)

    def add(self, key, value):
        return self.region.get_or_create(key, lambda: value)

    def delete(self, key):
        return self.region.delete(key)

    def get_multi(self, keys):
        values = self.region.get_multi(keys)
        return [None if value is cache.NO_VALUE else value for value in
                values]

    def delete_multi(self, keys):
        return self.region.delete_multi(keys)

函数get_client()代码实现:

def get_client(expiration_time=0):
    if CONF.memcached_servers:
        return CacheClient(
                 _get_custom_cache_region(expiration_time=expiration_time,
                                         backend='dogpile.cache.memcached',
                                         url=CONF.memcached_servers))
    elif CONF.cache.enabled:
        return CacheClient(
                 _get_default_cache_region(expiration_time=expiration_time))
    
    return CacheClient(
             _get_custom_cache_region(expiration_time=expiration_time,
                                     backend='oslo_cache.dict'))

其实上面所述的CacheClient中缓存各种操作的实现都是基于region(具体可参见dogpile.cache.region.pydogpile.cache.backends.memcached.py)来的,至于实现细节可阅读dogpile库的源码
来进一步深入。

3. oslo.messaging

此处不再展开,请参考我的另一篇博文Openstack基础组件之oslo.messaging即可。

4. oslo.service

该组件提供了一个框架,用于为Openstack应用定义长时间运行的服务,库的名称是oslo_service,在oslo.service的实现中,依赖于oslo_service.service的两个最核心的类:Service类和Launcher类。

  • Service类:基于抽象基类oslo_service.service.ServiceBase,它定义了一个服务对象以及管理整个服务生命周期的方法,包括reset、start、stop、wait,另外,在对服务对象实例化时可以传进一个threads的参数创建一个包含threads个线程的线程组ThreadGroup对象,用来管理服务中的所有线程。还有一个叫做Services的类,用来管理一组服务。
  • Launcher类:主要用来启动一个或多个服务并等待其完成。其定义了launcher_service(service, workers)、stop()、wait()、restart()方法管理Launcher对象中所有服务的生命周期,并且基于workers的数量又有两种实现机制:ServiceLauncher类和ProcessLauncher类。

实际使用场景下,我们在创建Service时会对oslo_service.service.Service进一步封装,比如下面这样:

from oslo_sevice import service
from oslo_config import cfg

CONF = cfg.CONF
class TestService(service.Service):
  def __init__(self, *args, **kwargs):
    pass

  def start(self):
    # do something
    pass

  def stop(self):
    pass

  def reset(self):
    pass

if __name__ == '__main__':
  service.launch(CONF, TestService()).wait()

你可能感兴趣的:(Openstack基础组件概览(1))