df95ad397e
Murano's application packages can now be stored either in database (using murano-api) or in Glance Artifact repository (so-called Glance V3 api). This patch adds an experimental support of the latter approach to murano engine. As all the difference between these two storages is incapsulated in the murano client, engine just needs to configure it properly by passing an instance of glance v3 client on creation. This is controlled by a 'packages_service' parameter of 'packages_opts' configuration group. It is set to 'murano' by default and indicates the usage of old, database-backed storage. If set to 'glance', the murano client will encapsulate glance v3 connector and thus the packages will be accessed from Glance Artifact Repository. The settings of Glance client are also added to the configuration, as well as a client factory to generate the client. As these settings may now conflict with the settings "demo plugin", the appropriate configuration section is renamed in the latter. This patch also contains a couple of utility functions to transform partial semver version specs into non-partial ones and - further - to a set of Glance query parameters needed to filter the artifacts based on that spec. Change-Id: I690467e43b6b63850ebecef756635241e623554c Implements-blueprint: artifact-repository-support
242 lines
9.1 KiB
Python
242 lines
9.1 KiB
Python
# Copyright (c) 2014 Mirantis, Inc.
|
|
#
|
|
# 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 weakref
|
|
|
|
from eventlet import semaphore
|
|
import heatclient.client as hclient
|
|
import keystoneclient
|
|
import keystoneclient.auth.identity.access as access
|
|
import muranoclient.v1.client as muranoclient
|
|
import neutronclient.v2_0.client as nclient
|
|
from oslo_config import cfg
|
|
|
|
from murano.common import auth_utils
|
|
from muranoclient.glance import client as art_client
|
|
|
|
try:
|
|
# integration with congress is optional
|
|
import congressclient.v1.client as congress_client
|
|
except ImportError as congress_client_import_error:
|
|
congress_client = None
|
|
try:
|
|
import mistralclient.api.client as mistralclient
|
|
except ImportError as mistral_import_error:
|
|
mistralclient = None
|
|
|
|
CONF = cfg.CONF
|
|
|
|
|
|
class ClientManager(object):
|
|
def __init__(self, environment):
|
|
self._trusts_keystone_client = None
|
|
self._token_keystone_client = None
|
|
self._cache = {}
|
|
self._semaphore = semaphore.BoundedSemaphore()
|
|
self._environment = weakref.proxy(environment)
|
|
|
|
def get_client(self, name, use_trusts, client_factory):
|
|
if not CONF.engine.use_trusts:
|
|
use_trusts = False
|
|
|
|
keystone_client = None if name == 'keystone' else \
|
|
self.get_keystone_client(use_trusts)
|
|
|
|
self._semaphore.acquire()
|
|
try:
|
|
client, used_token = self._cache.get(
|
|
(name, use_trusts), (None, None))
|
|
fresh_token = None if keystone_client is None \
|
|
else keystone_client.auth_token
|
|
if use_trusts and used_token != fresh_token:
|
|
client = None
|
|
if not client:
|
|
token = fresh_token
|
|
if not use_trusts:
|
|
token = self._environment.token
|
|
client = client_factory(keystone_client, token)
|
|
self._cache[(name, use_trusts)] = (client, token)
|
|
return client
|
|
finally:
|
|
self._semaphore.release()
|
|
|
|
def get_keystone_client(self, use_trusts=True):
|
|
if not CONF.engine.use_trusts:
|
|
use_trusts = False
|
|
factory = lambda _1, _2: \
|
|
auth_utils.get_client_for_trusts(self._environment.trust_id) \
|
|
if use_trusts else auth_utils.get_client(
|
|
self._environment.token, self._environment.tenant_id)
|
|
|
|
return self.get_client('keystone', use_trusts, factory)
|
|
|
|
def get_congress_client(self, use_trusts=True):
|
|
"""Client for congress services
|
|
|
|
:return: initialized congress client
|
|
:raise ImportError: in case that python-congressclient
|
|
is not present on python path
|
|
"""
|
|
|
|
if not congress_client:
|
|
# congress client was not imported
|
|
raise congress_client_import_error
|
|
if not CONF.engine.use_trusts:
|
|
use_trusts = False
|
|
|
|
def factory(keystone_client, auth_token):
|
|
auth = access.AccessInfoPlugin(keystone_client.auth_ref)
|
|
session = keystoneclient.session.Session(auth=auth)
|
|
return congress_client.Client(session=session,
|
|
service_type='policy')
|
|
|
|
return self.get_client('congress', use_trusts, factory)
|
|
|
|
def get_heat_client(self, use_trusts=True):
|
|
if not CONF.engine.use_trusts:
|
|
use_trusts = False
|
|
|
|
def factory(keystone_client, auth_token):
|
|
heat_settings = CONF.heat
|
|
|
|
heat_url = keystone_client.service_catalog.url_for(
|
|
service_type='orchestration',
|
|
endpoint_type=heat_settings.endpoint_type)
|
|
|
|
kwargs = {
|
|
'token': auth_token,
|
|
'ca_file': heat_settings.ca_file or None,
|
|
'cert_file': heat_settings.cert_file or None,
|
|
'key_file': heat_settings.key_file or None,
|
|
'insecure': heat_settings.insecure
|
|
}
|
|
|
|
if not CONF.engine.use_trusts:
|
|
kwargs.update({
|
|
'username': 'badusername',
|
|
'password': 'badpassword'
|
|
})
|
|
return hclient.Client('1', heat_url, **kwargs)
|
|
|
|
return self.get_client('heat', use_trusts, factory)
|
|
|
|
def get_neutron_client(self, use_trusts=True):
|
|
if not CONF.engine.use_trusts:
|
|
use_trusts = False
|
|
|
|
def factory(keystone_client, auth_token):
|
|
neutron_settings = CONF.neutron
|
|
|
|
neutron_url = keystone_client.service_catalog.url_for(
|
|
service_type='network',
|
|
endpoint_type=neutron_settings.endpoint_type)
|
|
|
|
return nclient.Client(
|
|
endpoint_url=neutron_url,
|
|
token=auth_token,
|
|
ca_cert=neutron_settings.ca_cert or None,
|
|
insecure=neutron_settings.insecure)
|
|
|
|
return self.get_client('neutron', use_trusts, factory)
|
|
|
|
def get_murano_client(self, use_trusts=True):
|
|
if not CONF.engine.use_trusts:
|
|
use_trusts = False
|
|
|
|
def factory(keystone_client, auth_token):
|
|
murano_settings = CONF.murano
|
|
|
|
murano_url = \
|
|
murano_settings.url or keystone_client.service_catalog.url_for(
|
|
service_type='application_catalog',
|
|
endpoint_type=murano_settings.endpoint_type)
|
|
|
|
if CONF.packages_opts.packages_service == 'glance':
|
|
glance_settings = CONF.glance
|
|
glance_url = (glance_settings.url or
|
|
keystone_client.service_catalog.url_for(
|
|
service_type='image',
|
|
endpoint_type=glance_settings.endpoint_type))
|
|
|
|
arts = art_client.Client(
|
|
endpoint=glance_url, token=auth_token,
|
|
insecure=glance_settings.insecure,
|
|
key_file=glance_settings.key_file or None,
|
|
ca_file=glance_settings.ca_file or None,
|
|
cert_file=glance_settings.cert_file or None,
|
|
type_name='murano',
|
|
type_version=1)
|
|
else:
|
|
arts = None
|
|
|
|
return muranoclient.Client(
|
|
endpoint=murano_url,
|
|
key_file=murano_settings.key_file or None,
|
|
ca_file=murano_settings.cacert or None,
|
|
cert_file=murano_settings.cert_file or None,
|
|
insecure=murano_settings.insecure,
|
|
auth_url=keystone_client.auth_url,
|
|
token=auth_token,
|
|
artifacts_client=arts)
|
|
|
|
return self.get_client('murano', use_trusts, factory)
|
|
|
|
def get_mistral_client(self, use_trusts=True):
|
|
if not mistralclient:
|
|
raise mistral_import_error
|
|
|
|
if not CONF.engine.use_trusts:
|
|
use_trusts = False
|
|
|
|
def factory(keystone_client, auth_token):
|
|
mistral_settings = CONF.mistral
|
|
|
|
endpoint_type = mistral_settings.endpoint_type
|
|
service_type = mistral_settings.service_type
|
|
|
|
mistral_url = keystone_client.service_catalog.url_for(
|
|
service_type=service_type,
|
|
endpoint_type=endpoint_type)
|
|
|
|
return mistralclient.client(mistral_url=mistral_url,
|
|
project_id=keystone_client.tenant_id,
|
|
endpoint_type=endpoint_type,
|
|
service_type=service_type,
|
|
auth_token=auth_token,
|
|
user_id=keystone_client.user_id)
|
|
|
|
return self.get_client('mistral', use_trusts, factory)
|
|
|
|
def get_artifacts_client(self, use_trusts=True):
|
|
if not CONF.engine.use_trusts:
|
|
use_trusts = False
|
|
|
|
def factory(keystone_client, auth_token):
|
|
glance_settings = CONF.glance
|
|
|
|
glance_url = (glance_settings.url or
|
|
keystone_client.service_catalog.url_for(
|
|
service_type='image',
|
|
endpoint_type=glance_settings.endpoint_type))
|
|
|
|
return art_client.Client(endpoint=glance_url, token=auth_token,
|
|
insecure=glance_settings.insecure,
|
|
key_file=glance_settings.key_file or None,
|
|
cacert=glance_settings.cacert or None,
|
|
cert_file=(glance_settings.cert_file or
|
|
None),
|
|
type_name='murano',
|
|
type_version=1)
|
|
return self.get_client('artifacts', use_trusts, factory)
|