openstack的公共库(oslo)的使用
来源:互联网 发布:mac os x 10.9.5 iso 编辑:程序博客网 时间:2024/06/06 02:34
为了降低代码冗余度,openstack社区开发了很多公共库。通过这些公共库,可以很容易弄出一个完善鉴权、分布式、易配置、带调用链日志的REST服务。
oslo库的缺点是需要的背景知识比较多,英文文档写的又很简单,要真正用起来,没有几个demo会寸步难行。本文的目的就是通过demo,降低大家使用oslo库的难度。
1. oslo常用组件的一览表
2. 配置文件 oslo.config
它把配置项直接融入你的代码内,例子如下:
app.conf
- [DEFAULT]
- username=app
- [rabbit]
- host = 192.168.1.7
- port = 5672
myconfig.py
- # -*- coding: utf-8 -*-
- import sys
- from oslo_config import cfg
- #默认组的配置项
- service_opts = [
- cfg.StrOpt('username',
- default='default',
- help='user name'),
- cfg.StrOpt('password',
- help='password')
- ]
- #自定义配置组
- rabbit_group = cfg.OptGroup(
- name='rabbit',
- title='RabbitMQ options'
- )
- # 配置组中的多配置项模式
- rabbit_Opts = [
- cfg.StrOpt('host',
- default='localhost',
- help='IP/hostname to listen on.'),
- cfg.IntOpt('port',
- default=5672,
- help='Port number to listen on.')
- ]
- CONF = cfg.CONF
- #注册默认组的配置项
- CONF.register_opts(service_opts)
- #配置组必须在其组件被注册前注册!
- CONF.register_group(rabbit_group)
- #注册配置组中含有多个配置项的模式,必须指明配置组
- CONF.register_opts(rabbit_Opts, rabbit_group)
- #设置默认的日志文件名
- CONF(sys.argv[1:], default_config_files=['app.conf'])
- #使用配置项
- print ("username=%s rabbitmq.host=%s " % (CONF.username, CONF.rabbit.host))
3. 工具库 oslo.utils
4. REST服务器 oslo.service
oslo.service比较负责,因为它透传了很多wsgi的参数,这些其实是开发者不希望直接看到的。下面的例子在oslo.service的基础上再封装了一个小的MiniService,这样用起来会比较方便。
- # -*- coding: utf-8 -*-
- import sys
- from webob import Request
- #引入配置文件
- from oslo_config import cfg
- #引入带调用链的日志
- from oslo_log import log as logging
- from oslo_context import context
- #引入REST服务
- from oslo_service import service
- from oslo_service import wsgi
- CONF = cfg.CONF
- LOG = logging.getLogger(__name__)
- logging.register_options(CONF)
- logging.setup(CONF, "m19k")
- #mini服务
- class MiniService:
- def __init__(self, host = "0.0.0.0", port = "9000", workers = 1, use_ssl = False, cert_file = None, ca_file = None):
- self.host = host
- self.port = port
- self.workers = workers
- self.use_ssl = use_ssl
- self.cert_file = cert_file
- self.ca_file = ca_file
- self._actions = {}
- def add_action(self, url_path, action):
- if (url_path.lower() == "default") or (url_path == "/") or (url_path == ""):
- url_path = "default"
- elif (not url_path.startswith("/")):
- url_path = "/" + url_path
- self._actions[url_path] = action
- def _app(self, environ, start_response):
- context.RequestContext()
- LOG.debug("start action.")
- request = Request(environ)
- action = self._actions.get(environ['PATH_INFO'])
- if action == None:
- action = self._actions.get("default")
- if action != None:
- result = action(environ, request.method, request.path_info, request.query_string, request.body)
- try:
- result[1]
- except Exception,e:
- result = ('200 OK', str(result))
- start_response(result[0], [('Content-Type', 'text/plain')])
- return result[1]
- start_response("200 OK",[('Content-type', 'text/html')])
- return "mini service is ok\n"
- def start(self):
- self.server = wsgi.Server(CONF,
- "m19k",
- self._app,
- host = self.host,
- port = self.port,
- use_ssl = self.use_ssl)
- launcher = service.ProcessLauncher(CONF)
- launcher.launch_service(self.server, workers = self.workers)
- LOG.debug("launch service (%s:%s)." % (self.host, self.port))
- launcher.wait()
- # -*- coding: utf-8 -*-
- import sys
- from oslo_config import cfg
- from oslo_log import log as logging
- import miniservice
- CONF = cfg.CONF
- LOG = logging.getLogger(__name__)
- def default_action(env, method, path, query, body):
- LOG.info("demo action (method:%s, path:%s, query:%s, body:%s)"
- % (method, path, query, body))
- return ("200 OK", "default")
- def test_action(env, method, path, query, body):
- LOG.info("test (method:%s, path:%s, query:%s, body:%s)"
- % (method, path, query, body))
- return ("200 OK", "test")
- if __name__ == "__main__":
- CONF(sys.argv[1:])
- host = getattr(CONF, "host", "0.0.0.0")
- port = getattr(CONF, "port", "8001")
- service = miniservice.MiniService(host, port)
- service.add_action("", default_action)
- service.add_action("test", test_action)
- service.start()
通过curl即可测试
- curl http://localhost:8001/test -H "content-type:application/json" -X POST -d "{'a':'b', 'c':'1'}"
- # -*- coding: utf-8 -*-
- import uuid
- import socket
- import functools
- import requests
- from oslo_config import cfg
- from oslo_log import log as logging
- from oslo_serialization import jsonutils
- client_opts = [
- cfg.BoolOpt('debug',
- default=False,
- help="Print log in every request"),
- ]
- CONF = cfg.CONF
- CONF.register_opts(client_opts)
- LOG = logging.getLogger(__name__)
- class HttpClient(object):
- def __init__(self, cert=None, timeout=None, session=None):
- self.cert = cert
- self.timeout = None
- if not session:
- session = requests.Session()
- # Use TCPKeepAliveAdapter to fix bug 1323862
- for scheme in list(session.adapters):
- session.mount(scheme, TCPKeepAliveAdapter())
- self.session = session
- def request(self, url, method, json=None, connect_retries=0, **kwargs):
- #设置Http头,一般用于存储认证信息和格式信息
- headers = kwargs.setdefault('headers', dict())
- if self.cert:
- kwargs.setdefault('cert', self.cert)
- if self.timeout is not None:
- kwargs.setdefault('timeout', self.timeout)
- user_agent = headers.setdefault('User-Agent', uuid.uuid4().hex)
- if json is not None:
- headers['Content-Type'] = 'application/json'
- kwargs['data'] = jsonutils.dumps(json)
- #设置重试
- send = functools.partial(self._send_request, url, method, connect_retries)
- #获取response
- resp = send(**kwargs)
- return resp
- def _send_request(self, url, method, connect_retries, connect_retry_delay=0.5, **kwargs):
- try:
- if CONF.debug:
- LOG.debug("REQ:{url:%s, method:%s}" % (url, method))
- resp = self.session.request(method, url, **kwargs)
- except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e:
- if connect_retries <= 0:
- raise
- time.sleep(connect_retry_delay)
- return self._send_request(
- url, method, connect_retries=connect_retries - 1,
- connect_retry_delay=connect_retry_delay * 2,
- **kwargs)
- if CONF.debug:
- LOG.debug("RESP:{url:%s, method:%s, status:%s}" % (url, method, resp.status_code))
- return resp
- def head(self, url, **kwargs):
- return self.request(url, 'HEAD', **kwargs)
- def get(self, url, **kwargs):
- return self.request(url, 'GET', **kwargs)
- def post(self, url, **kwargs):
- return self.request(url, 'POST', **kwargs)
- def put(self, url, **kwargs):
- return self.request(url, 'PUT', **kwargs)
- def delete(self, url, **kwargs):
- return self.request(url, 'DELETE', **kwargs)
- def patch(self, url, **kwargs):
- return self.request(url, 'PATCH', **kwargs)
- #用于解决TCP Keep-Alive的补丁
- class TCPKeepAliveAdapter(requests.adapters.HTTPAdapter):
- def init_poolmanager(self, *args, **kwargs):
- if 'socket_options' not in kwargs:
- socket_options = [
- # Keep Nagle's algorithm off
- (socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),
- # Turn on TCP Keep-Alive
- (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
- ]
- if hasattr(socket, 'TCP_KEEPIDLE'):
- socket_options += [
- # Wait 60 seconds before sending keep-alive probes
- (socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60)
- ]
- if hasattr(socket, 'TCP_KEEPCNT'):
- socket_options += [
- # Set the maximum number of keep-alive probes
- (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 4)
- ]
- if hasattr(socket, 'TCP_KEEPINTVL'):
- socket_options += [
- # Send keep-alive probes every 15 seconds
- (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 15)
- ]
- kwargs['socket_options'] = socket_options
- super(TCPKeepAliveAdapter, self).init_poolmanager(*args, **kwargs)
- httpclient = HttpClient()
- print httpclient.request("http://localhost:8001/test", "POST", "{'a':'b'}")
5. 日志和调用链 oslo.log + oslo.context
纯粹的oslo.log是很容易使用的,参见下面的例子:
- from oslo_config import cfg
- from oslo_log import log as logging
- LOG = logging.getLogger(__name__)
- CONF = cfg.CONF
- DOMAIN = "demo"
- logging.register_options(CONF)
- logging.setup(CONF, DOMAIN)
- # Oslo Logging uses INFO as default
- LOG.info("Oslo Logging")
- LOG.warning("Oslo Logging")
- LOG.error("Oslo Logging")
在上述miniservice中,在REST的入口处,通过
- context.RequestContext()
6. RPC调用 oslo.messaging
一个服务对外是REST接口,而服务内部的多个组件走的是RPC。Openstack中,RPC一般用rabbitmq来实现,oslo.messaging就是封装它的。可惜的是,它也要让读者有amqp的背景知识。
server.py
- from oslo_config import cfg
- import oslo_messaging
- from oslo_log import log as logging
- import time
- CONF = cfg.CONF
- LOG = logging.getLogger(__name__)
- logging.register_options(CONF)
- logging.setup(CONF, "myservice")
- CONF(default_config_files=['app.conf'])
- class ServerControlEndpoint(object):
- target = oslo_messaging.Target(namespace='control',
- version='2.0')
- def __init__(self, server):
- self.server = server
- def stop(self, ctx):
- if self.server:
- self.server.stop()
- class TestEndpoint(object):
- def test(self, ctx, arg):
- print "test"
- print arg
- return arg
- transport = oslo_messaging.get_transport(cfg.CONF)
- target = oslo_messaging.Target(topic='test123', server='server1')
- endpoints = [
- ServerControlEndpoint(None),
- TestEndpoint(),
- ]
- server = oslo_messaging.get_rpc_server(transport, target, endpoints,
- executor='blocking')
- try:
- server.start()
- while True:
- time.sleep(1)
- except KeyboardInterrupt:
- print("Stopping server")
- server.stop()
- server.wait()
- import oslo_messaging as messaging
- from oslo_context import context
- from oslo_config import cfg
- from oslo_log import log as logging
- CONF = cfg.CONF
- LOG = logging.getLogger(__name__)
- logging.register_options(CONF)
- logging.setup(CONF, "myservice")
- CONF(default_config_files=['app.conf'])
- ctxt = {}
- arg = {'a':'b'}
- transport = messaging.get_transport(cfg.CONF)
- target = messaging.Target(topic='test123')
- client = messaging.RPCClient(transport, target)
- client.call(ctxt, 'test', arg=arg)
0 0
- openstack的公共库(oslo)的使用
- openstack的公共库(oslo)的使用
- openstack的公共库(oslo)的使用
- OpenStack配置解析库oslo.config的使用方法
- OpenStack配置解析库oslo.config的使用方法
- OpenStack配置解析库oslo.config的使用方法
- OpenStack配置解析库oslo.config的使用方法
- OpenStack oslo.messaging使用
- openstack oslo.messaging库
- OpenStack公共组件oslo之一——oslo.config
- OpenStack公共组件oslo之二——oslo.utils
- OpenStack公共组件oslo之三——oslo.log
- OpenStack公共组件oslo之四——oslo.context
- OpenStack公共组件oslo之五——oslo.service
- OpenStack公共组件oslo之六——oslo.messaging
- OpenStack公共组件oslo之七——oslo.middleware
- OpenStack公共组件oslo之八——oslo.i18n
- OpenStack公共组件oslo之九——oslo.db
- EventBus简单使用和源码解析
- 2-段寄存器
- 音频资源地址
- UML学习2 - 用例图
- 《JAVA与模式》之策略模式
- openstack的公共库(oslo)的使用
- shell 后台执行以及隐藏脚本中调用其他脚本隐藏输出
- 随机生成10条不重复长度为10以内的字符串,进行排序
- 制作可以 SSH 登录的 Docker 镜像
- repo sync单独下载manifest中某一个project
- 观察者模式详解(包含观察者模式JDK的漏洞以及事件驱动模型)
- Python 学习笔记(3)——元组和字典
- Android 用sharepreference在各个程序之间共享数据
- tez中的brocast join