parent
b5f33280a1
commit
4e04023955
|
@ -12,8 +12,9 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pbr.version
|
||||
from os_namos import sync
|
||||
|
||||
|
||||
__version__ = pbr.version.VersionInfo(
|
||||
'os-namos').version_string()
|
||||
RegistrationInfo = sync.RegistrationInfo
|
||||
Config = sync.Config
|
||||
register_myself = sync.register_myself
|
||||
collect_registration_info = sync.collect_registration_info
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
import os_namos # noqa
|
||||
|
||||
PROJECT_NAME = 'namos'
|
||||
VERSION = '0.0.1'
|
||||
MESSAGE_QUEUE_CONDUCTOR_TOPIC = '%s.conductor' % PROJECT_NAME
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def init_conf(prog):
|
||||
CONF(project=PROJECT_NAME,
|
||||
version=VERSION,
|
||||
prog=prog)
|
||||
|
||||
|
||||
def init_log(project=PROJECT_NAME):
|
||||
logging.register_options(cfg.CONF)
|
||||
logging.setup(cfg.CONF,
|
||||
project,
|
||||
version=VERSION)
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class NamosException(Exception):
|
||||
def __init__(self, **kwargs):
|
||||
self.message = kwargs.get('message') or "UNKNOWN"
|
||||
self.data = kwargs.get('data') or {}
|
||||
self.error_code = kwargs.get('error_code') or -1
|
||||
self.http_status_code = kwargs.get('http_status_code') or 500
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self.message).encode('UTF-8')
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.message)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return self.__class__(**self.kwargs)
|
|
@ -0,0 +1,111 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
import oslo_messaging
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from oslo_context import context
|
||||
|
||||
DEFAULT_URL = "__default__"
|
||||
TRANSPORTS = {}
|
||||
|
||||
_ALIASES = {
|
||||
'namos.openstack.common.rpc.impl_kombu': 'rabbit',
|
||||
'namos.openstack.common.rpc.impl_qpid': 'qpid',
|
||||
'namos.openstack.common.rpc.impl_zmq': 'zmq',
|
||||
}
|
||||
|
||||
|
||||
class RequestContextSerializer(oslo_messaging.Serializer):
|
||||
def __init__(self, base):
|
||||
self._base = base
|
||||
|
||||
def serialize_entity(self, ctxt, entity):
|
||||
if not self._base:
|
||||
return entity
|
||||
return self._base.serialize_entity(ctxt, entity)
|
||||
|
||||
def deserialize_entity(self, ctxt, entity):
|
||||
if not self._base:
|
||||
return entity
|
||||
return self._base.deserialize_entity(ctxt, entity)
|
||||
|
||||
@staticmethod
|
||||
def serialize_context(ctxt):
|
||||
return ctxt.to_dict()
|
||||
|
||||
@staticmethod
|
||||
def deserialize_context(ctxt):
|
||||
return context.RequestContext(ctxt)
|
||||
|
||||
|
||||
class JsonPayloadSerializer(oslo_messaging.NoOpSerializer):
|
||||
@classmethod
|
||||
def serialize_entity(cls, context, entity):
|
||||
return jsonutils.to_primitive(entity, convert_instances=True)
|
||||
|
||||
|
||||
def get_transport(url=None, optional=False, cache=True):
|
||||
"""Initialise the olso.messaging layer."""
|
||||
global TRANSPORTS, DEFAULT_URL
|
||||
cache_key = url or DEFAULT_URL
|
||||
transport = TRANSPORTS.get(cache_key)
|
||||
if not transport or not cache:
|
||||
try:
|
||||
transport = oslo_messaging.get_transport(cfg.CONF, url,
|
||||
aliases=_ALIASES)
|
||||
except oslo_messaging.InvalidTransportURL as e:
|
||||
if not optional or e.url:
|
||||
# NOTE(sileht): olso.messaging is configured but unloadable
|
||||
# so reraise the exception
|
||||
raise
|
||||
return None
|
||||
else:
|
||||
if cache:
|
||||
TRANSPORTS[cache_key] = transport
|
||||
return transport
|
||||
|
||||
|
||||
def get_rpc_server(host, topic, version, endpoint):
|
||||
"""Return a configured olso.messaging rpc server."""
|
||||
|
||||
target = oslo_messaging.Target(server=host, topic=topic, version=version)
|
||||
serializer = RequestContextSerializer(JsonPayloadSerializer())
|
||||
transport = get_transport(optional=True)
|
||||
return oslo_messaging.get_rpc_server(transport, target,
|
||||
[endpoint], executor='eventlet',
|
||||
serializer=serializer)
|
||||
|
||||
|
||||
def get_rpc_client(topic, version, retry=None, **kwargs):
|
||||
"""Return a configured olso.messaging RPCClient."""
|
||||
|
||||
target = oslo_messaging.Target(version=version,
|
||||
topic=topic, **kwargs)
|
||||
serializer = RequestContextSerializer(JsonPayloadSerializer())
|
||||
transport = get_transport(optional=True)
|
||||
return oslo_messaging.RPCClient(transport, target,
|
||||
serializer=serializer,
|
||||
retry=retry,
|
||||
version_cap=version)
|
||||
|
||||
|
||||
def cleanup():
|
||||
"""Cleanup the olso.messaging layer."""
|
||||
global TRANSPORTS
|
||||
|
||||
for url in TRANSPORTS:
|
||||
TRANSPORTS[url].cleanup()
|
||||
del TRANSPORTS[url]
|
|
@ -0,0 +1,67 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Client side of the OSLO CONFIG NAMOS
|
||||
"""
|
||||
import functools
|
||||
|
||||
import json
|
||||
import oslo_messaging
|
||||
from oslo_messaging import RemoteError
|
||||
|
||||
from os_namos.common import config # noqa
|
||||
from os_namos.common import exception as namos_exception
|
||||
from os_namos.common import messaging as rpc
|
||||
|
||||
|
||||
def wrapper_function(func):
|
||||
@functools.wraps(func)
|
||||
def wrapped(*args, **kwargs):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except RemoteError as e:
|
||||
kwargs = json.loads(e.value)
|
||||
raise namos_exception.NamosException(**kwargs)
|
||||
|
||||
return wrapped
|
||||
|
||||
|
||||
class ConductorAPI(object):
|
||||
RPC_API_VERSION = '1.0'
|
||||
|
||||
def __init__(self, project):
|
||||
super(ConductorAPI, self).__init__()
|
||||
self.topic = 'namos.conductor'
|
||||
|
||||
# Setup the messaging tweaks ! here
|
||||
rpc._ALIASES.update(
|
||||
{
|
||||
'%s.openstack.common.rpc.impl_kombu' % project: 'rabbit',
|
||||
'%s.openstack.common.rpc.impl_qpid' % project: 'qpid',
|
||||
'%s.openstack.common.rpc.impl_zmq' % project: 'zmq',
|
||||
}
|
||||
)
|
||||
|
||||
oslo_messaging.set_transport_defaults(project)
|
||||
|
||||
self.client = rpc.get_rpc_client(version=self.RPC_API_VERSION,
|
||||
topic=self.topic)
|
||||
|
||||
@wrapper_function
|
||||
def register_myself(self, context, registration_info):
|
||||
# TODO(mrkanag): is to be call instead of cast
|
||||
return self.client.cast(context,
|
||||
'register_myself',
|
||||
registration_info=registration_info)
|
|
@ -0,0 +1,158 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import socket
|
||||
|
||||
from oslo_context import context
|
||||
|
||||
from os_namos.common import rpcapi
|
||||
|
||||
|
||||
NAMOS_RPCAPI = None
|
||||
|
||||
|
||||
class RegistrationInfo(object):
|
||||
def __init__(self,
|
||||
host,
|
||||
project_name,
|
||||
prog_name,
|
||||
fqdn=socket.gethostname(),
|
||||
pid=os.getpid(),
|
||||
config_file_list=None,
|
||||
config_dict=None):
|
||||
self.host = host
|
||||
self.project_name = project_name
|
||||
self.fqdn = fqdn
|
||||
self.prog_name = prog_name
|
||||
self.pid = pid
|
||||
self.config_file_list = config_file_list or list()
|
||||
|
||||
# List of configuration which CONF is already updated with
|
||||
self.config_dict = config_dict or dict()
|
||||
|
||||
|
||||
class Config(object):
|
||||
def __init__(self,
|
||||
name,
|
||||
type,
|
||||
value,
|
||||
help=None,
|
||||
default_value=None,
|
||||
required=False,
|
||||
secret=False,
|
||||
file=None):
|
||||
self.name = name
|
||||
self.default_value = default_value
|
||||
self.help = help
|
||||
self.type = type
|
||||
self.value = value
|
||||
self.required = required
|
||||
self.secret = secret
|
||||
self.file = file
|
||||
|
||||
|
||||
def collect_registration_info():
|
||||
from oslo_config import cfg
|
||||
self = cfg.CONF
|
||||
|
||||
def normalize_type(type):
|
||||
if str(type).find('function'):
|
||||
return 'String'
|
||||
return type
|
||||
|
||||
def get_host():
|
||||
try:
|
||||
return getattr(self, 'host')
|
||||
except: # noqa
|
||||
import socket
|
||||
return socket.gethostname()
|
||||
|
||||
reg_info = RegistrationInfo(host=get_host(),
|
||||
project_name=self.project,
|
||||
prog_name=self.prog,
|
||||
config_file_list=self.default_config_files)
|
||||
|
||||
config_dict = dict()
|
||||
for opt_name in sorted(self._opts):
|
||||
opt = self._get_opt_info(opt_name)['opt']
|
||||
cfg = Config(name='%s' % opt_name,
|
||||
type='%s' % normalize_type(opt.type),
|
||||
value='%s' % getattr(self, opt_name),
|
||||
help='%s' % opt.help,
|
||||
required=opt.required,
|
||||
secret=opt.secret,
|
||||
default_value='%s' % opt.default)
|
||||
config_dict[cfg.name] = cfg
|
||||
|
||||
for group_name in self._groups:
|
||||
group_attr = self.GroupAttr(self, self._get_group(group_name))
|
||||
for opt_name in sorted(self._groups[group_name]._opts):
|
||||
opt = self._get_opt_info(opt_name, group_name)['opt']
|
||||
cfg = Config(name="%s.%s" % (group_name, opt_name),
|
||||
type='%s' % normalize_type(opt.type),
|
||||
value='%s' % getattr(group_attr, opt_name),
|
||||
help='%s' % opt.help,
|
||||
required=opt.required,
|
||||
secret=opt.secret,
|
||||
default_value='%s' % opt.default)
|
||||
config_dict[cfg.name] = cfg
|
||||
reg_info.config_dict = config_dict
|
||||
|
||||
return reg_info
|
||||
|
||||
|
||||
def register_myself(registration_info=None):
|
||||
global NAMOS_RPCAPI
|
||||
|
||||
if registration_info is None:
|
||||
registration_info = collect_registration_info()
|
||||
|
||||
if NAMOS_RPCAPI is None:
|
||||
NAMOS_RPCAPI = rpcapi.ConductorAPI(
|
||||
project=registration_info.project_name)
|
||||
|
||||
ctx = context.RequestContext()
|
||||
return NAMOS_RPCAPI.register_myself(ctx, registration_info)
|
||||
|
||||
|
||||
def add_config(config):
|
||||
pass
|
||||
|
||||
|
||||
def remove_config(config):
|
||||
pass
|
||||
|
||||
|
||||
def update_config(config):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# TODO(mrkanag) Remove this before production !
|
||||
from os_namos.common import config
|
||||
|
||||
config.init_log()
|
||||
config.init_conf('test-run')
|
||||
|
||||
reg_info = RegistrationInfo(
|
||||
host='namos_development',
|
||||
project_name=config.PROJECT_NAME,
|
||||
prog_name='sync',
|
||||
config_file_list=['/etc/namos/namos.conf'],
|
||||
config_dict={})
|
||||
|
||||
print (reg_info.__dict__)
|
||||
|
||||
print (register_myself(reg_info))
|
|
@ -3,3 +3,7 @@
|
|||
# process, which may cause wedges in the gate later.
|
||||
|
||||
pbr>=1.6
|
||||
oslo.context>=0.2.0 # Apache-2.0
|
||||
oslo.serialization>=1.10.0 # Apache-2.0
|
||||
oslo.messaging>=4.0.0 # Apache-2.0
|
||||
oslo.utils>=3.5.0 # Apache-2.0
|
Loading…
Reference in New Issue