From 71df0a289d78019dc96168da719c940c9d62e735 Mon Sep 17 00:00:00 2001 From: chenke Date: Tue, 17 Sep 2019 15:42:12 +0800 Subject: [PATCH] Fix the hardcoding of user role using sdk_adapter approach 1. Refer to nova's latest code, use get_sdk to create the client[1]. 2. Move placement_client define from default to seperate placement file. Note: The new method for get nova and placement client has been tested in latest cyborg devstack environment. And the test results are good. Because now cyborg does not have unit tests for the common and conf directory, unit tests related to this patch will be added in the future, but not in this patch. Reference: [1]. https://github.com/openstack/nova/blob/3f019f2db373d82cbc93f0a30de0059d3d07432b/nova/utils.py#L1013 Change-Id: I2a335d47ee3cc24f78b4d49942f1cccd586a0dcc --- cyborg/common/exception.py | 4 +++ cyborg/common/nova_client.py | 11 ++------ cyborg/common/placement_client.py | 15 ++--------- cyborg/common/utils.py | 45 ++++++++++++++++++++++++++++++- cyborg/conf/__init__.py | 5 +++- cyborg/conf/default.py | 43 ----------------------------- cyborg/conf/nova.py | 42 +++++++++++++++++++++++++++++ cyborg/conf/placement.py | 42 +++++++++++++++++++++++++++++ devstack/lib/cyborg | 15 +++++++++-- 9 files changed, 153 insertions(+), 69 deletions(-) create mode 100644 cyborg/conf/nova.py create mode 100644 cyborg/conf/placement.py 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