e798119841
Flame needed pemanent adjustments to mathe the changes in the python-openstackclients. We now use openstacksdk or shade which will handle themselves the compatibility. We also made flame modular so that any-one can add features by implementing there own flame managers and adding their modules to the `openstack_flame` entry point. This new flame version is also fully compatible with python 3. Change-Id: I586a165b5022031963f504874bd50e1b11fe0d27
279 lines
9.9 KiB
Python
279 lines
9.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# This software is released under the MIT License.
|
|
#
|
|
# Copyright (c) 2018 Orange Cloud for Business / Cloudwatt
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
|
|
import argparse
|
|
import logging
|
|
import sys
|
|
|
|
from keystoneauth1 import loading
|
|
from keystoneauth1 import session as keystone_session
|
|
from openstack import connection as os_connection
|
|
# We get a subclass of openstack.config.loader.OpenStackConfig which is more
|
|
# complete:
|
|
from os_client_config.config import OpenStackConfig # noqa
|
|
from shade.openstackcloud import OpenStackCloud # noqa
|
|
|
|
from flameclient import utils
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
def list_auth_types():
|
|
return [loader for loader in loading.get_available_plugin_loaders()]
|
|
|
|
|
|
def get_loader(auth_type):
|
|
if auth_type not in list_auth_types():
|
|
raise ValueError(
|
|
"'auth_type' has to be one of %s (received %s)" % (
|
|
list_auth_types(), auth_type
|
|
)
|
|
)
|
|
return loading.get_plugin_loader(auth_type)
|
|
|
|
|
|
def extract_loader_kwargs(loader, **kwargs):
|
|
"""Get keystoneauth1.loading.get_plugin_loader's auth kwargs
|
|
|
|
Return the specific auth kwargs and remaining kwargs
|
|
"""
|
|
loader_keys = [option.dest for option in loader.get_options()]
|
|
loader_kwargs = {
|
|
key: kwargs[key] for key in loader_keys if key in kwargs
|
|
}
|
|
remaining_kwargs = {
|
|
key: kwargs[key] for key in kwargs if key not in loader_keys
|
|
}
|
|
return loader_kwargs, remaining_kwargs
|
|
|
|
|
|
def get_openstack_config_with_envvars(
|
|
parser, config=None, load_envvars=False, load_yaml_config=False
|
|
):
|
|
"""Add openstack_options to argparse.ArgumentParser
|
|
|
|
:param argparse.ArgumentParser parser: argparse.ArgumentParser instance
|
|
or None.
|
|
|
|
:param bool load_envvars:
|
|
Whether or not to load config settings from environment variables.
|
|
Defaults to True.
|
|
|
|
:returns: OpenStackConfig instance
|
|
"""
|
|
|
|
if config is None:
|
|
# If we use `openstack.config.loader.OpenStackConfig` instead of
|
|
# `os_client_config.config.OpenStackConfig` and then instantiate a
|
|
# `shade.openstackcloud.OpenStackCloud` instance as `cloud`, when
|
|
# trying to access the `cloud.keystone_client` attribute (or any other
|
|
# `*_client attribute`), we get a
|
|
# "TypeError: 'NoneType' object is not callable" exception
|
|
# This is why we use `os_client_config.config.OpenStackConfig`: it's to
|
|
# have all `shade.openstackcloud.OpenStackCloud` attributes working
|
|
# properly. Whether we use them or not, whether these attributes are
|
|
# deprecated or not, we do not want a 'broken' shade instance in case
|
|
# third party managers would use them.
|
|
config = OpenStackConfig(
|
|
load_envvars=load_envvars, load_yaml_config=load_yaml_config
|
|
)
|
|
if parser:
|
|
if load_envvars or load_yaml_config:
|
|
config.register_argparse_arguments(parser, sys.argv)
|
|
else:
|
|
config.register_argparse_arguments(parser, [])
|
|
return config
|
|
|
|
|
|
def get_openstack_cli_arguments(
|
|
parser=None, load_envvars=True, load_yaml_config=True,
|
|
renamed_args=False
|
|
):
|
|
if parser is None:
|
|
parser = argparse.ArgumentParser()
|
|
get_openstack_config_with_envvars(
|
|
parser, load_envvars=load_envvars, load_yaml_config=load_yaml_config
|
|
)
|
|
known_args, unknown_args = parser.parse_known_args()
|
|
if renamed_args:
|
|
known_args = utils.rename_os_options(known_args, clean=False)
|
|
return known_args, unknown_args
|
|
|
|
|
|
def get_openstack_envvars_as_kwargs(
|
|
with_args=False, parser=None, load_envvars=True, load_yaml_config=True
|
|
):
|
|
"""Get openstack environment variables"""
|
|
known_args, unknown_args = get_openstack_cli_arguments(
|
|
parser=parser, load_envvars=load_envvars,
|
|
load_yaml_config=load_yaml_config
|
|
)
|
|
kwargs = utils.rename_os_kwargs(vars(known_args), clean=True)
|
|
if with_args:
|
|
return known_args, unknown_args, kwargs
|
|
return kwargs
|
|
|
|
|
|
def get_keystoneauth1_session(
|
|
load_envvars=False, load_yaml_config=False, **kwargs
|
|
):
|
|
if load_envvars:
|
|
kwargs.update(
|
|
get_openstack_envvars_as_kwargs(
|
|
load_envvars=load_envvars, load_yaml_config=load_yaml_config
|
|
)
|
|
)
|
|
auth_type = kwargs.get('auth_type', 'password')
|
|
loader = get_loader(auth_type)
|
|
loader_kwargs, _ = extract_loader_kwargs(loader, **kwargs)
|
|
auth = loader.load_from_options(**loader_kwargs)
|
|
return keystone_session.Session(auth=auth)
|
|
|
|
|
|
get_keystone_session = get_keystoneauth1_session
|
|
|
|
|
|
def get_openstack_config(
|
|
parser_or_options=None, load_envvars=False, load_yaml_config=False,
|
|
**kwargs
|
|
):
|
|
"""Same as os_client_config.get_config with less errors.
|
|
|
|
Indeed, if we source OS_* variable environments, and one calls:
|
|
|
|
os_client_config.get_config(
|
|
load_envvars=False, load_yaml_config=False, **kwargs
|
|
)
|
|
|
|
we get this kind of error:
|
|
|
|
ConfigException: Region fr1 is not a valid region name for cloud
|
|
envvars. Valid choices are fr0. Please note that region names are case
|
|
sensitive.
|
|
|
|
It seems like os_client_config.get_config fails to NOT handle envvars.
|
|
|
|
Also, os_client_config.get_config saves the config in a global variable...
|
|
This is absolutely not thread safe...
|
|
|
|
"""
|
|
parsed_options = None
|
|
parser = None
|
|
if isinstance(parser_or_options, argparse.ArgumentParser):
|
|
parser = parser_or_options
|
|
config = get_openstack_config_with_envvars(
|
|
parser=parser, load_envvars=load_envvars,
|
|
load_yaml_config=load_yaml_config
|
|
)
|
|
if parser_or_options is not None:
|
|
if isinstance(parser_or_options, argparse.Namespace):
|
|
parsed_options = parser_or_options
|
|
elif isinstance(parser_or_options, dict):
|
|
parsed_options = utils.dict_to_options(parser_or_options)
|
|
elif isinstance(parser_or_options, argparse.ArgumentParser):
|
|
if load_envvars or load_yaml_config:
|
|
parsed_options, _ = parser_or_options.parse_known_args(
|
|
sys.argv)
|
|
else:
|
|
parsed_options, _ = parser_or_options.parse_known_args([])
|
|
else:
|
|
raise AttributeError(
|
|
"'parser_options' has to be an 'argparse.ArgumentParser' or "
|
|
"'argparse.Namespace' instance or dict or None. "
|
|
"Received '%s'" % type(parser_or_options)
|
|
)
|
|
return config.get_one(
|
|
options=parsed_options,
|
|
load_yaml_config=load_yaml_config,
|
|
load_envvars=load_envvars,
|
|
**kwargs
|
|
)
|
|
|
|
|
|
def get_openstack_sdk_connection(
|
|
parser_or_options=None, load_envvars=False, load_yaml_config=False,
|
|
cloud_config=None, session=None,
|
|
**kwargs
|
|
):
|
|
if session is not None:
|
|
return os_connection.Connection(session=session, **kwargs)
|
|
|
|
if cloud_config is None:
|
|
# we could return
|
|
# `openstack.connect(load_envvars=load_envvars, load_yaml_config=load_yaml_config, **kwargs)` # noqa
|
|
# but by doing so magic things are lacking in the config and we have
|
|
# random failing methods on the instance. See comments in
|
|
# get_openstack_config_with_envvars for more information.
|
|
cloud_config = get_openstack_config(
|
|
parser_or_options=parser_or_options, load_envvars=load_envvars,
|
|
load_yaml_config=load_yaml_config,
|
|
**kwargs
|
|
)
|
|
if isinstance(parser_or_options, dict):
|
|
parser_or_options = utils.dict_to_options(parser_or_options)
|
|
return os_connection.from_config(
|
|
cloud_config=cloud_config, options=parser_or_options
|
|
)
|
|
|
|
|
|
def get_shade(
|
|
parser_or_options=None, cloud_config=None, connection=None,
|
|
load_envvars=False, load_yaml_config=False,
|
|
**kwargs
|
|
):
|
|
"""Get shade instance
|
|
|
|
You can use an `argparse.ArgumentParser` or `argparse.Namespace` instance
|
|
with `load_envvars` and/or `load_yaml_config` set to True,
|
|
Or you kan use kwargs to authenticate with `load_envvars` AND
|
|
`load_yaml_config` set to False:
|
|
|
|
cloud = get_shade(
|
|
auth_type='password',
|
|
auth_url='https://identity.fr1.cloudwatt.com/v2.0',
|
|
interface='public',
|
|
password='YourPassword',
|
|
project_id='Your ProjectID,
|
|
project_name='YourProjectName,
|
|
region_name='YourRegionName',
|
|
username='YourUserName'
|
|
)
|
|
|
|
You can also use a token instead of password with kwargs, If so, use
|
|
`auth_type='token'`.
|
|
|
|
"""
|
|
if cloud_config is not None:
|
|
return OpenStackCloud(cloud_config=cloud_config, **kwargs)
|
|
elif connection is not None:
|
|
return OpenStackCloud(cloud_config=connection.config, **kwargs)
|
|
else:
|
|
return OpenStackCloud(
|
|
cloud_config=get_openstack_config(
|
|
parser_or_options=parser_or_options, load_envvars=load_envvars,
|
|
load_yaml_config=load_yaml_config,
|
|
**kwargs
|
|
)
|
|
)
|