Add cyborg-api command
Change-Id: I392ad0383d5d8299db407df79bd60adbfbd428cd
This commit is contained in:
parent
9fa1a7183c
commit
c7b24fda7f
19
cyborg/cmd/__init__.py
Normal file
19
cyborg/cmd/__init__.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 oslo_i18n as i18n
|
||||
|
||||
|
||||
i18n.install('cyborg')
|
36
cyborg/cmd/api.py
Normal file
36
cyborg/cmd/api.py
Normal file
@ -0,0 +1,36 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""The Cyborg Service API."""
|
||||
|
||||
import sys
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from cyborg.common import service as cyborg_service
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def main():
|
||||
# Parse config file and command line options, then start logging
|
||||
cyborg_service.prepare_service(sys.argv)
|
||||
|
||||
# Build and start the WSGI app
|
||||
launcher = cyborg_service.process_launcher()
|
||||
server = cyborg_service.WSGIService('cyborg_api', CONF.api.enable_ssl_api)
|
||||
launcher.launch_service(server, workers=server.workers)
|
||||
launcher.wait()
|
0
cyborg/common/__init__.py
Normal file
0
cyborg/common/__init__.py
Normal file
26
cyborg/common/config.py
Normal file
26
cyborg/common/config.py
Normal file
@ -0,0 +1,26 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 cyborg import version
|
||||
|
||||
|
||||
def parse_args(argv, default_config_files=None):
|
||||
version_string = version.version_info.release_string()
|
||||
cfg.CONF(argv[1:],
|
||||
project='cyborg',
|
||||
version=version_string,
|
||||
default_config_files=default_config_files)
|
90
cyborg/common/exception.py
Normal file
90
cyborg/common/exception.py
Normal file
@ -0,0 +1,90 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Cyborg base exception handling.
|
||||
|
||||
SHOULD include dedicated exception logging.
|
||||
|
||||
"""
|
||||
|
||||
from oslo_log import log
|
||||
import six
|
||||
from six.moves import http_client
|
||||
|
||||
from cyborg.common.i18n import _
|
||||
from cyborg.conf import CONF
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class CyborgException(Exception):
|
||||
"""Base Cyborg Exception
|
||||
|
||||
To correctly use this class, inherit from it and define
|
||||
a '_msg_fmt' property. That message will get printf'd
|
||||
with the keyword arguments provided to the constructor.
|
||||
|
||||
If you need to access the message from an exception you should use
|
||||
six.text_type(exc)
|
||||
|
||||
"""
|
||||
_msg_fmt = _("An unknown exception occurred.")
|
||||
code = http_client.INTERNAL_SERVER_ERROR
|
||||
headers = {}
|
||||
safe = False
|
||||
|
||||
def __init__(self, message=None, **kwargs):
|
||||
self.kwargs = kwargs
|
||||
|
||||
if 'code' not in self.kwargs:
|
||||
try:
|
||||
self.kwargs['code'] = self.code
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if not message:
|
||||
try:
|
||||
message = self._msg_fmt % kwargs
|
||||
except Exception:
|
||||
# kwargs doesn't match a variable in self._msg_fmt
|
||||
# log the issue and the kwargs
|
||||
LOG.exception('Exception in string format operation')
|
||||
for name, value in kwargs.items():
|
||||
LOG.error("%s: %s" % (name, value))
|
||||
|
||||
if CONF.fatal_exception_format_errors:
|
||||
raise
|
||||
else:
|
||||
# at least get the core self._msg_fmt out if something
|
||||
# happened
|
||||
message = self._msg_fmt
|
||||
|
||||
super(CyborgException, self).__init__(message)
|
||||
|
||||
def __str__(self):
|
||||
"""Encode to utf-8 then wsme api can consume it as well."""
|
||||
if not six.PY3:
|
||||
return unicode(self.args[0]).encode('utf-8')
|
||||
|
||||
return self.args[0]
|
||||
|
||||
def __unicode__(self):
|
||||
"""Return a unicode representation of the exception message."""
|
||||
return unicode(self.args[0])
|
||||
|
||||
|
||||
class ConfigInvalid(CyborgException):
|
||||
_msg_fmt = _("Invalid configuration file. %(error_msg)s")
|
22
cyborg/common/i18n.py
Normal file
22
cyborg/common/i18n.py
Normal file
@ -0,0 +1,22 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 oslo_i18n as i18n
|
||||
|
||||
|
||||
_translators = i18n.TranslatorFactory(domain='cyborg')
|
||||
|
||||
# The primary translation function using the well-known name "_"
|
||||
_ = _translators.primary
|
121
cyborg/common/rpc.py
Normal file
121
cyborg/common/rpc.py
Normal file
@ -0,0 +1,121 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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_context import context as cyborg_context
|
||||
import oslo_messaging as messaging
|
||||
from oslo_messaging.rpc import dispatcher
|
||||
|
||||
from cyborg.common import exception
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
TRANSPORT = None
|
||||
NOTIFICATION_TRANSPORT = None
|
||||
NOTIFIER = None
|
||||
|
||||
ALLOWED_EXMODS = [
|
||||
exception.__name__,
|
||||
]
|
||||
EXTRA_EXMODS = []
|
||||
|
||||
|
||||
def init(conf):
|
||||
global TRANSPORT, NOTIFICATION_TRANSPORT, NOTIFIER
|
||||
exmods = get_allowed_exmods()
|
||||
TRANSPORT = messaging.get_rpc_transport(conf,
|
||||
allowed_remote_exmods=exmods)
|
||||
NOTIFICATION_TRANSPORT = messaging.get_notification_transport(
|
||||
conf,
|
||||
allowed_remote_exmods=exmods)
|
||||
serializer = RequestContextSerializer(messaging.JsonPayloadSerializer())
|
||||
NOTIFIER = messaging.Notifier(NOTIFICATION_TRANSPORT,
|
||||
serializer=serializer,
|
||||
topics=['notifications'])
|
||||
|
||||
|
||||
def cleanup():
|
||||
global TRANSPORT, NOTIFICATION_TRANSPORT, NOTIFIER
|
||||
assert TRANSPORT is not None
|
||||
assert NOTIFICATION_TRANSPORT is not None
|
||||
assert NOTIFIER is not None
|
||||
TRANSPORT.cleanup()
|
||||
NOTIFICATION_TRANSPORT.cleanup()
|
||||
TRANSPORT = NOTIFICATION_TRANSPORT = NOTIFIER = None
|
||||
|
||||
|
||||
def set_defaults(control_exchange):
|
||||
messaging.set_transport_defaults(control_exchange)
|
||||
|
||||
|
||||
def add_extra_exmods(*args):
|
||||
EXTRA_EXMODS.extend(args)
|
||||
|
||||
|
||||
def clear_extra_exmods():
|
||||
del EXTRA_EXMODS[:]
|
||||
|
||||
|
||||
def get_allowed_exmods():
|
||||
return ALLOWED_EXMODS + EXTRA_EXMODS
|
||||
|
||||
|
||||
class RequestContextSerializer(messaging.Serializer):
|
||||
def __init__(self, base):
|
||||
self._base = base
|
||||
|
||||
def serialize_entity(self, context, entity):
|
||||
if not self._base:
|
||||
return entity
|
||||
return self._base.serialize_entity(context, entity)
|
||||
|
||||
def deserialize_entity(self, context, entity):
|
||||
if not self._base:
|
||||
return entity
|
||||
return self._base.deserialize_entity(context, entity)
|
||||
|
||||
def serialize_context(self, context):
|
||||
return context.to_dict()
|
||||
|
||||
def deserialize_context(self, context):
|
||||
return cyborg_context.RequestContext.from_dict(context)
|
||||
|
||||
|
||||
def get_client(target, version_cap=None, serializer=None):
|
||||
assert TRANSPORT is not None
|
||||
serializer = RequestContextSerializer(serializer)
|
||||
return messaging.RPCClient(TRANSPORT,
|
||||
target,
|
||||
version_cap=version_cap,
|
||||
serializer=serializer)
|
||||
|
||||
|
||||
def get_server(target, endpoints, serializer=None):
|
||||
assert TRANSPORT is not None
|
||||
access_policy = dispatcher.DefaultRPCAccessPolicy
|
||||
serializer = RequestContextSerializer(serializer)
|
||||
return messaging.get_rpc_server(TRANSPORT,
|
||||
target,
|
||||
endpoints,
|
||||
executor='eventlet',
|
||||
serializer=serializer,
|
||||
access_policy=access_policy)
|
||||
|
||||
|
||||
def get_notifier(service=None, host=None, publisher_id=None):
|
||||
assert NOTIFIER is not None
|
||||
if not publisher_id:
|
||||
publisher_id = "%s.%s" % (service, host or CONF.host)
|
||||
return NOTIFIER.prepare(publisher_id=publisher_id)
|
98
cyborg/common/service.py
Normal file
98
cyborg/common/service.py
Normal file
@ -0,0 +1,98 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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_concurrency import processutils
|
||||
from oslo_log import log
|
||||
from oslo_service import service
|
||||
from oslo_service import wsgi
|
||||
|
||||
from cyborg.api import app
|
||||
from cyborg.common import config
|
||||
from cyborg.common import exception
|
||||
from cyborg.common.i18n import _
|
||||
from cyborg.common import rpc
|
||||
from cyborg.conf import CONF
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def prepare_service(argv=None):
|
||||
log.register_options(CONF)
|
||||
log.set_defaults()
|
||||
rpc.set_defaults(control_exchange='cyborg')
|
||||
|
||||
argv = argv or []
|
||||
config.parse_args(argv)
|
||||
|
||||
log.setup(CONF, 'cyborg')
|
||||
rpc.init(CONF)
|
||||
|
||||
|
||||
def process_launcher():
|
||||
return service.ProcessLauncher(CONF)
|
||||
|
||||
|
||||
class WSGIService(service.ServiceBase):
|
||||
"""Provides ability to launch cyborg API from wsgi app."""
|
||||
|
||||
def __init__(self, name, use_ssl=False):
|
||||
"""Initialize, but do not start the WSGI server.
|
||||
|
||||
:param name: The name of the WSGI server given to the loader.
|
||||
:param use_ssl: Wraps the socket in an SSL context if True.
|
||||
:returns: None
|
||||
"""
|
||||
self.name = name
|
||||
self.app = app.setup_app()
|
||||
self.workers = (CONF.api.api_workers or
|
||||
processutils.get_worker_count())
|
||||
if self.workers and self.workers < 1:
|
||||
raise exception.ConfigInvalid(
|
||||
_("api_workers value of %d is invalid, "
|
||||
"must be greater than 0.") % self.workers)
|
||||
|
||||
self.server = wsgi.Server(CONF, self.name, self.app,
|
||||
host=CONF.api.host_ip,
|
||||
port=CONF.api.port,
|
||||
use_ssl=use_ssl)
|
||||
|
||||
def start(self):
|
||||
"""Start serving this service using loaded configuration.
|
||||
|
||||
:returns: None
|
||||
"""
|
||||
self.server.start()
|
||||
|
||||
def stop(self):
|
||||
"""Stop serving this API.
|
||||
|
||||
:returns: None
|
||||
"""
|
||||
self.server.stop()
|
||||
|
||||
def wait(self):
|
||||
"""Wait for the service to stop serving this API.
|
||||
|
||||
:returns: None
|
||||
"""
|
||||
self.server.wait()
|
||||
|
||||
def reset(self):
|
||||
"""Reset server greenpool size to default.
|
||||
|
||||
:returns: None
|
||||
"""
|
||||
self.server.reset()
|
25
cyborg/conf/__init__.py
Normal file
25
cyborg/conf/__init__.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 cyborg.conf import api
|
||||
from cyborg.conf import default
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
api.register_opts(CONF)
|
||||
default.register_opts(CONF)
|
49
cyborg/conf/api.py
Normal file
49
cyborg/conf/api.py
Normal file
@ -0,0 +1,49 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 cyborg.common.i18n import _
|
||||
|
||||
|
||||
opts = [
|
||||
cfg.HostAddressOpt('host_ip',
|
||||
default='0.0.0.0',
|
||||
help=_('The IP address on which cyborg-api listens.')),
|
||||
cfg.PortOpt('port',
|
||||
default=6666,
|
||||
help=_('The TCP port on which cyborg-api listens.')),
|
||||
cfg.IntOpt('api_workers',
|
||||
help=_('Number of workers for OpenStack Cyborg API service. '
|
||||
'The default is equal to the number of CPUs available '
|
||||
'if that can be determined, else a default worker '
|
||||
'count of 1 is returned.')),
|
||||
cfg.BoolOpt('enable_ssl_api',
|
||||
default=False,
|
||||
help=_("Enable the integrated stand-alone API to service "
|
||||
"requests via HTTPS instead of HTTP. If there is a "
|
||||
"front-end service performing HTTPS offloading from "
|
||||
"the service, this option should be False; note, you "
|
||||
"will want to change public API endpoint to represent "
|
||||
"SSL termination URL with 'public_endpoint' option.")),
|
||||
]
|
||||
|
||||
opt_group = cfg.OptGroup(name='api',
|
||||
title='Options for the cyborg-api service')
|
||||
|
||||
|
||||
def register_opts(conf):
|
||||
conf.register_group(opt_group)
|
||||
conf.register_opts(opts, group=opt_group)
|
32
cyborg/conf/default.py
Normal file
32
cyborg/conf/default.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 cyborg.common.i18n import _
|
||||
|
||||
|
||||
exc_log_opts = [
|
||||
cfg.BoolOpt('fatal_exception_format_errors',
|
||||
default=False,
|
||||
help=_('Used if there is a formatting error when generating '
|
||||
'an exception message (a programming error). If True, '
|
||||
'raise an exception; if False, use the unformatted '
|
||||
'message.')),
|
||||
]
|
||||
|
||||
|
||||
def register_opts(conf):
|
||||
conf.register_opts(exc_log_opts)
|
19
cyborg/version.py
Normal file
19
cyborg/version.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 pbr.version
|
||||
|
||||
|
||||
version_info = pbr.version.VersionInfo('cyborg')
|
@ -6,3 +6,12 @@ pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||
pecan!=1.0.2,!=1.0.3,!=1.0.4,!=1.2,>=1.0.0 # BSD
|
||||
WSME>=0.8 # MIT
|
||||
six>=1.9.0 # MIT
|
||||
eventlet!=0.18.3,!=0.20.1,<0.21.0,>=0.18.2 # MIT
|
||||
oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0
|
||||
oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
|
||||
oslo.log>=3.22.0 # Apache-2.0
|
||||
oslo.context>=2.14.0 # Apache-2.0
|
||||
oslo.messaging!=5.25.0,>=5.24.2 # Apache-2.0
|
||||
oslo.concurrency>=3.8.0 # Apache-2.0
|
||||
oslo.service>=1.10.0 # Apache-2.0
|
||||
oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0
|
||||
|
Loading…
Reference in New Issue
Block a user