diff --git a/cyborg/common/exception.py b/cyborg/common/exception.py index 7c05a3f3..318e323f 100644 --- a/cyborg/common/exception.py +++ b/cyborg/common/exception.py @@ -196,6 +196,10 @@ class NotFound(CyborgException): code = http_client.NOT_FOUND +class ServiceUnavailable(Invalid): + msg_fmt = _("Service is unavailable at this time.") + + class ServiceNotFound(NotFound): msg_fmt = _("Service %(service_id)s could not be found.") diff --git a/cyborg/common/nova_client.py b/cyborg/common/nova_client.py index 79f4ada2..6fa38cf1 100644 --- a/cyborg/common/nova_client.py +++ b/cyborg/common/nova_client.py @@ -12,8 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. -from cyborg.conf import CONF -from openstack import connection +from cyborg.common import utils from oslo_log import log as logging LOG = logging.getLogger(__name__) @@ -21,13 +20,7 @@ LOG = logging.getLogger(__name__) class NovaAPI(object): def __init__(self): - default_user = "devstack-admin" - try: - auth_user = CONF.compute.username - except Exception: - auth_user = default_user - self.conn = connection.Connection(cloud=auth_user) - self.nova_client = self.conn.compute + self.nova_client = utils.get_sdk_adapter('compute') def _get_acc_changed_event(self, instance_uuid, dev_profile_name, status): return [{'name': 'accelerator-requests-bound', diff --git a/cyborg/common/placement_client.py b/cyborg/common/placement_client.py index 0f90762f..d83bcd6e 100644 --- a/cyborg/common/placement_client.py +++ b/cyborg/common/placement_client.py @@ -14,33 +14,22 @@ # under the License. from cyborg.common import exception -from cyborg.conf import CONF +from cyborg.common import utils from keystoneauth1 import exceptions as ks_exc from oslo_log import log as logging from oslo_middleware import request_id -from openstack import connection - LOG = logging.getLogger(__name__) NESTED_PROVIDER_API_VERSION = '1.14' POST_RPS_RETURNS_PAYLOAD_API_VERSION = '1.20' PLACEMENT_CLIENT_SEMAPHORE = 'placement_client' -_CONN = None class PlacementClient(object): """Client class for reporting to placement.""" def __init__(self): - global _CONN - if _CONN is None: - default_user = 'devstack-admin' - try: - auth_user = CONF.placement.username or default_user - except Exception: - auth_user = default_user - _CONN = connection.Connection(cloud=auth_user) - self._client = _CONN.placement + self._client = utils.get_sdk_adapter('placement') def get(self, url, version=None, global_request_id=None): return self._client.get(url, microversion=version, diff --git a/cyborg/common/utils.py b/cyborg/common/utils.py index c60e3cfb..96300a81 100644 --- a/cyborg/common/utils.py +++ b/cyborg/common/utils.py @@ -19,17 +19,19 @@ import six from keystoneauth1 import exceptions as ks_exc from keystoneauth1 import loading as ks_loading +from openstack import connection +from openstack import exceptions as sdk_exc from os_service_types import service_types from oslo_concurrency import lockutils from oslo_log import log from cyborg.common import exception +from cyborg.common.i18n import _ import cyborg.conf LOG = log.getLogger(__name__) - synchronized = lockutils.synchronized_with_prefix('cyborg-') _SERVICE_TYPES = service_types.ServiceTypes() CONF = cyborg.conf.CONF @@ -111,6 +113,47 @@ def get_ksa_adapter(service_type, ksa_auth=None, ksa_session=None, min_version=min_version, max_version=max_version) +def _get_conf_group(service_type): + # Get the conf group corresponding to the service type. + confgrp = _SERVICE_TYPES.get_project_name(service_type) + if not confgrp or not hasattr(CONF, confgrp): + raise exception.ConfGroupForServiceTypeNotFound(stype=service_type) + return confgrp + + +def _get_auth_and_session(confgrp): + ksa_auth = ks_loading.load_auth_from_conf_options(CONF, confgrp) + return ks_loading.load_session_from_conf_options( + CONF, confgrp, auth=ksa_auth) + + +def get_sdk_adapter(service_type, check_service=False): + """Construct an openstacksdk-brokered Adapter for a given service type. + We expect to find a conf group whose name corresponds to the service_type's + project according to the service-types-authority. That conf group must + provide ksa auth, session, and adapter options. + :param service_type: String name of the service type for which the Adapter + is to be constructed. + :param check_service: If True, we will query the endpoint to make sure the + service is alive, raising ServiceUnavailable if it is not. + :return: An openstack.proxy.Proxy object for the specified service_type. + :raise: ConfGroupForServiceTypeNotFound If no conf group name could be + found for the specified service_type. + :raise: ServiceUnavailable if check_service is True and the service is down + """ + confgrp = _get_conf_group(service_type) + sess = _get_auth_and_session(confgrp) + try: + conn = connection.Connection( + session=sess, oslo_conf=CONF, service_types={service_type}, + strict_proxies=check_service) + except sdk_exc.ServiceDiscoveryException as e: + raise exception.ServiceUnavailable( + _("The %(service_type)s service is unavailable: %(error)s") % + {'service_type': service_type, 'error': six.text_type(e)}) + return getattr(conn, service_type) + + def get_endpoint(ksa_adapter): """Get the endpoint URL represented by a keystoneauth1 Adapter. diff --git a/cyborg/conf/__init__.py b/cyborg/conf/__init__.py index 3a7876c1..e1a5889d 100644 --- a/cyborg/conf/__init__.py +++ b/cyborg/conf/__init__.py @@ -21,6 +21,8 @@ from cyborg.conf import database from cyborg.conf import default from cyborg.conf import glance from cyborg.conf import keystone +from cyborg.conf import nova +from cyborg.conf import placement from cyborg.conf import service_token CONF = cfg.CONF @@ -29,7 +31,8 @@ api.register_opts(CONF) agent.register_opts(CONF) database.register_opts(CONF) default.register_opts(CONF) -default.register_placement_opts(CONF) service_token.register_opts(CONF) glance.register_opts(CONF) keystone.register_opts(CONF) +nova.register_opts(CONF) +placement.register_opts(CONF) diff --git a/cyborg/conf/default.py b/cyborg/conf/default.py index 433d52ef..73ab3050 100644 --- a/cyborg/conf/default.py +++ b/cyborg/conf/default.py @@ -18,11 +18,9 @@ import os import socket -from keystoneauth1 import loading as k_loading from oslo_config import cfg from cyborg.common.i18n import _ -from cyborg.conf import utils as confutils exc_log_opts = [ @@ -65,33 +63,6 @@ path_opts = [ help=_("Top-level directory for maintaining cyborg's state.")), ] -PLACEMENT_CONF_SECTION = 'placement' -DEFAULT_SERVICE_TYPE = 'placement' - -placement_group = cfg.OptGroup( - PLACEMENT_CONF_SECTION, - title='Placement Service Options', - help="Configuration options for connecting to the placement API service") - -placement_opts = [ - cfg.StrOpt('endpoint_type', - default='public', - choices=['public', 'admin', 'internal'], - help=_('Type of the placement endpoint to use. This endpoint ' - 'will be looked up in the keystone catalog and should ' - 'be one of public, internal or admin.')), - cfg.BoolOpt( - 'randomize_allocation_candidates', - default=False, - help=_('If True, when limiting allocation candidate results, the ' - 'results will be a random sampling of the full result set. ' - 'If False, allocation candidates are returned in a ' - 'deterministic but undefined order. That is, all things ' - 'being equal, two requests for allocation candidates will ' - 'return the same results in the same order; but no guarantees ' - 'are made as to how that order is determined.')), -] - def register_opts(conf): conf.register_opts(exc_log_opts) @@ -99,24 +70,10 @@ def register_opts(conf): conf.register_opts(path_opts) -def register_placement_opts(cfg=cfg.CONF): - cfg.register_group(placement_group) - cfg.register_opts(placement_opts, group=PLACEMENT_CONF_SECTION) - confutils.register_ksa_opts(cfg, placement_group, DEFAULT_SERVICE_TYPE) - - DEFAULT_OPTS = (exc_log_opts + service_opts + path_opts) def list_opts(): return { - PLACEMENT_CONF_SECTION: ( - placement_opts + - k_loading.get_session_conf_options() + - k_loading.get_auth_common_conf_options() + - k_loading.get_auth_plugin_conf_options('password') + - k_loading.get_auth_plugin_conf_options('v2password') + - k_loading.get_auth_plugin_conf_options('v3password') + - confutils.get_ksa_adapter_opts(DEFAULT_SERVICE_TYPE)), 'DEFAULT': DEFAULT_OPTS } diff --git a/cyborg/conf/nova.py b/cyborg/conf/nova.py new file mode 100644 index 00000000..edd5dab4 --- /dev/null +++ b/cyborg/conf/nova.py @@ -0,0 +1,42 @@ +# 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 keystoneauth1 import loading as ks_loading +from oslo_config import cfg + +from cyborg.conf import utils as confutils + + +DEFAULT_SERVICE_TYPE = 'compute' + + +nova_group = cfg.OptGroup( + 'nova', + title='Nova Service Options', + help="Configuration options for connecting to the Nova API service") + + +def register_opts(conf): + conf.register_group(nova_group) + confutils.register_ksa_opts(conf, nova_group, DEFAULT_SERVICE_TYPE) + + +def list_opts(): + return { + nova_group.name: ( + ks_loading.get_session_conf_options() + + ks_loading.get_auth_common_conf_options() + + ks_loading.get_auth_plugin_conf_options('password') + + ks_loading.get_auth_plugin_conf_options('v2password') + + ks_loading.get_auth_plugin_conf_options('v3password') + + confutils.get_ksa_adapter_opts(DEFAULT_SERVICE_TYPE)) + } diff --git a/cyborg/conf/placement.py b/cyborg/conf/placement.py new file mode 100644 index 00000000..cf63314f --- /dev/null +++ b/cyborg/conf/placement.py @@ -0,0 +1,42 @@ +# 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 keystoneauth1 import loading as ks_loading +from oslo_config import cfg + +from cyborg.conf import utils as confutils + + +PLACEMENT_CONF_SECTION = 'placement' +DEFAULT_SERVICE_TYPE = 'placement' + +placement_group = cfg.OptGroup( + PLACEMENT_CONF_SECTION, + title='Placement Service Options', + help="Configuration options for connecting to the placement API service") + + +def register_opts(conf): + conf.register_group(placement_group) + confutils.register_ksa_opts(conf, placement_group, DEFAULT_SERVICE_TYPE) + + +def list_opts(): + return { + PLACEMENT_CONF_SECTION: ( + ks_loading.get_session_conf_options() + + ks_loading.get_auth_common_conf_options() + + ks_loading.get_auth_plugin_conf_options('password') + + ks_loading.get_auth_plugin_conf_options('v2password') + + ks_loading.get_auth_plugin_conf_options('v3password') + + confutils.get_ksa_adapter_opts(DEFAULT_SERVICE_TYPE)) + } diff --git a/devstack/lib/cyborg b/devstack/lib/cyborg index 18f66551..56e092b0 100644 --- a/devstack/lib/cyborg +++ b/devstack/lib/cyborg @@ -199,7 +199,6 @@ function configure_cyborg_placement { # Use the provided config file path or default to $CYBORG_CONF. local section=${1:-placement} local auth_section=${2:-keystone_authtoken} - iniset $CYBORG_CONF_FILE $section auth_section $auth_section iniset $CYBORG_CONF_FILE $section auth_type "password" iniset $CYBORG_CONF_FILE $section auth_url "$KEYSTONE_SERVICE_URI" iniset $CYBORG_CONF_FILE $section username $section @@ -218,7 +217,6 @@ function configure_cyborg_placement { function configure_cyborg_glance { local section=${1:-glance} local auth_section=${2:-keystone_authtoken} - iniset $CYBORG_CONF_FILE $section auth_section $auth_section iniset $CYBORG_CONF_FILE $section auth_type "password" iniset $CYBORG_CONF_FILE $section auth_url "$KEYSTONE_SERVICE_URI" iniset $CYBORG_CONF_FILE $section username $section @@ -229,6 +227,18 @@ function configure_cyborg_glance { iniset $CYBORG_CONF_FILE $section api_servers "$GLANCE_URL" } +function configure_cyborg_nova { + local section=${1:-nova} + local auth_section=${2:-keystone_authtoken} + iniset $CYBORG_CONF_FILE $section auth_type "password" + iniset $CYBORG_CONF_FILE $section auth_url "$KEYSTONE_SERVICE_URI" + iniset $CYBORG_CONF_FILE $section username $section + iniset $CYBORG_CONF_FILE $section password "$SERVICE_PASSWORD" + iniset $CYBORG_CONF_FILE $section user_domain_name "$SERVICE_DOMAIN_NAME" + iniset $CYBORG_CONF_FILE $section project_name "$SERVICE_TENANT_NAME" + iniset $CYBORG_CONF_FILE $section project_domain_name "$SERVICE_DOMAIN_NAME" +} + # configure_cyborg_conductor() - Is used by configure_cyborg(). # Sets conductor specific settings. function configure_cyborg_conductor { @@ -240,6 +250,7 @@ function configure_cyborg_conductor { configure_auth_for service_catalog configure_cyborg_placement configure_cyborg_glance + configure_cyborg_nova sudo cp $CYBORG_DIR/etc/cyborg/rootwrap.conf $CYBORG_ROOTWRAP_CONF sudo cp -r $CYBORG_DIR/etc/cyborg/rootwrap.d $CYBORG_CONF_DIR