165 lines
6.7 KiB
Python
165 lines
6.7 KiB
Python
# 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.
|
|
|
|
"""Utilities and helper functions."""
|
|
|
|
import six
|
|
|
|
from keystoneauth1 import loading as ks_loading
|
|
from os_service_types import service_types
|
|
from oslo_concurrency import lockutils
|
|
from oslo_log import log
|
|
|
|
from cyborg.common import exception
|
|
import cyborg.conf
|
|
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
synchronized = lockutils.synchronized_with_prefix('cyborg-')
|
|
_SERVICE_TYPES = service_types.ServiceTypes()
|
|
CONF = cyborg.conf.CONF
|
|
|
|
|
|
def safe_rstrip(value, chars=None):
|
|
"""Removes trailing characters from a string if that does not make it empty
|
|
|
|
:param value: A string value that will be stripped.
|
|
:param chars: Characters to remove.
|
|
:return: Stripped value.
|
|
|
|
"""
|
|
if not isinstance(value, six.string_types):
|
|
LOG.warning("Failed to remove trailing character. Returning "
|
|
"original object. Supplied object is not a string: "
|
|
"%s,", value)
|
|
return value
|
|
|
|
return value.rstrip(chars) or value
|
|
|
|
|
|
def get_ksa_adapter(service_type, ksa_auth=None, ksa_session=None,
|
|
min_version=None, max_version=None):
|
|
"""Construct a keystoneauth1 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 at least ksa adapter options. Depending how the result is to be
|
|
used, ksa auth and/or session options may also be required, or the relevant
|
|
parameter supplied.
|
|
|
|
:param service_type: String name of the service type for which the Adapter
|
|
is to be constructed.
|
|
:param ksa_auth: A keystoneauth1 auth plugin. If not specified, we attempt
|
|
to find one in ksa_session. Failing that, we attempt to
|
|
load one from the conf.
|
|
:param ksa_session: A keystoneauth1 Session. If not specified, we attempt
|
|
to load one from the conf.
|
|
:param min_version: The minimum major version of the adapter's endpoint,
|
|
intended to be used as the lower bound of a range with
|
|
max_version.
|
|
If min_version is given with no max_version it is as
|
|
if max version is 'latest'.
|
|
:param max_version: The maximum major version of the adapter's endpoint,
|
|
intended to be used as the upper bound of a range with
|
|
min_version.
|
|
:return: A keystoneauth1 Adapter object for the specified service_type.
|
|
:raise: ConfGroupForServiceTypeNotFound If no conf group name could be
|
|
found for the specified 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):
|
|
# Try the service type as the conf group. This is necessary for e.g.
|
|
# placement, while it's still part of the nova project.
|
|
# Note that this might become the first thing we try if/as we move to
|
|
# using service types for conf group names in general.
|
|
confgrp = service_type
|
|
if not confgrp or not hasattr(CONF, confgrp):
|
|
raise exception.ConfGroupForServiceTypeNotFound(stype=service_type)
|
|
|
|
# Ensure we have an auth.
|
|
# NOTE(efried): This could be None, and that could be okay - e.g. if the
|
|
# result is being used for get_endpoint() and the conf only contains
|
|
# endpoint_override.
|
|
if not ksa_auth:
|
|
if ksa_session and ksa_session.auth:
|
|
ksa_auth = ksa_session.auth
|
|
else:
|
|
ksa_auth = ks_loading.load_auth_from_conf_options(CONF, confgrp)
|
|
|
|
if not ksa_session:
|
|
ksa_session = ks_loading.load_session_from_conf_options(
|
|
CONF, confgrp, auth=ksa_auth)
|
|
|
|
return ks_loading.load_adapter_from_conf_options(
|
|
CONF, confgrp, session=ksa_session, auth=ksa_auth,
|
|
min_version=min_version, max_version=max_version)
|
|
|
|
|
|
def get_endpoint(ksa_adapter):
|
|
"""Get the endpoint URL represented by a keystoneauth1 Adapter.
|
|
|
|
This method is equivalent to what
|
|
|
|
ksa_adapter.get_endpoint()
|
|
|
|
should do, if it weren't for a panoply of bugs.
|
|
|
|
:param ksa_adapter: keystoneauth1.adapter.Adapter, appropriately set up
|
|
with an endpoint_override; or service_type, interface
|
|
(list) and auth/service_catalog.
|
|
:return: String endpoint URL.
|
|
:raise EndpointNotFound: If endpoint discovery fails.
|
|
"""
|
|
# TODO(efried): This will be unnecessary once bug #1707993 is fixed.
|
|
# (At least for the non-image case, until 1707995 is fixed.)
|
|
if ksa_adapter.endpoint_override:
|
|
return ksa_adapter.endpoint_override
|
|
# TODO(efried): Remove this once bug #1707995 is fixed.
|
|
if ksa_adapter.service_type == 'image':
|
|
try:
|
|
# LOG.warning(ksa_adapter.__dict__)
|
|
return ksa_adapter.get_endpoint_data().catalog_url
|
|
except AttributeError:
|
|
# ksa_adapter.auth is a _ContextAuthPlugin, which doesn't have
|
|
# get_endpoint_data. Fall through to using get_endpoint().
|
|
pass
|
|
# TODO(efried): The remainder of this method reduces to
|
|
# TODO(efried): return ksa_adapter.get_endpoint()
|
|
# TODO(efried): once bug #1709118 is fixed.
|
|
# NOTE(efried): Id9bd19cca68206fc64d23b0eaa95aa3e5b01b676 may also do the
|
|
# trick, once it's in a ksa release.
|
|
# The EndpointNotFound exception happens when _ContextAuthPlugin is in play
|
|
# because its get_endpoint() method isn't yet set up to handle interface as
|
|
# a list. (It could also happen with a real auth if the endpoint isn't
|
|
# there; but that's covered below.)
|
|
try:
|
|
return ksa_adapter.get_endpoint()
|
|
except ks_exc.EndpointNotFound:
|
|
pass
|
|
|
|
interfaces = list(ksa_adapter.interface)
|
|
for interface in interfaces:
|
|
ksa_adapter.interface = interface
|
|
try:
|
|
return ksa_adapter.get_endpoint()
|
|
except ks_exc.EndpointNotFound:
|
|
pass
|
|
raise ks_exc.EndpointNotFound(
|
|
"Could not find requested endpoint for any of the following "
|
|
"interfaces: %s" % interfaces)
|