Merge Connection and OpenStackCloud

There's no good reason to have the shade functions in a cloud attribute.
Go ahead and dive all the way in and make OpenStackCloud a mixin class.

There was one wrapped exception that got removed and thus the test to test
that we were wrapping it.

Change-Id: Iebd80fe5bc511ea879ea71aa88ce7d79c5e8fa58
This commit is contained in:
Monty Taylor 2018-01-30 16:22:20 -06:00
parent 8483e1b139
commit 0a6083b876
No known key found for this signature in database
GPG Key ID: 7BAE94BC7141A594
22 changed files with 227 additions and 299 deletions

@ -24,6 +24,17 @@ already. For reference, those are:
* Plumbed Proxy use of Adapter through the Adapter subclass from shade that * Plumbed Proxy use of Adapter through the Adapter subclass from shade that
uses the TaskManager to run REST calls. uses the TaskManager to run REST calls.
* Finish migrating to Resource2 and Proxy2, rename them to Resource and Proxy. * Finish migrating to Resource2 and Proxy2, rename them to Resource and Proxy.
* Merge OpenStackCloud into Connection. This should result
in being able to use the connection interact with the cloud using all three
interfaces. For instance:
.. code-block:: python
conn = connection.Connection()
servers = conn.list_servers() # High-level resource interface from shade
servers = conn.compute.servers() # SDK Service/Object Interface
response = conn.compute.get('/servers') # REST passthrough
Next steps Next steps
========== ==========
@ -40,17 +51,6 @@ Next steps
shade integration shade integration
----------------- -----------------
* Merge OpenStackCloud into Connection. This should result
in being able to use the connection interact with the cloud using all three
interfaces. For instance:
.. code-block:: python
conn = connection.Connection()
servers = conn.list_servers() # High-level resource interface from shade
servers = conn.compute.servers() # SDK Service/Object Interface
response = conn.compute.get('/servers') # REST passthrough
* Invent some terminology that is clear and makes sense to distinguish between * Invent some terminology that is clear and makes sense to distinguish between
the object interface that came originally from python-openstacksdk and the the object interface that came originally from python-openstacksdk and the
interface that came from shade. interface that came from shade.

@ -11,6 +11,7 @@ Connection Object
.. autoclass:: openstack.connection.Connection .. autoclass:: openstack.connection.Connection
:members: :members:
:inherited-members:
Transitioning from Profile Transitioning from Profile

@ -56,6 +56,8 @@ def openstack_clouds(
def openstack_cloud( def openstack_cloud(
config=None, strict=False, app_name=None, app_version=None, **kwargs): config=None, strict=False, app_name=None, app_version=None, **kwargs):
# Late import while we unwind things
from openstack import connection
if not config: if not config:
config = _get_openstack_config(app_name, app_version) config = _get_openstack_config(app_name, app_version)
try: try:
@ -63,4 +65,4 @@ def openstack_cloud(
except keystoneauth1.exceptions.auth_plugins.NoMatchingPlugin as e: except keystoneauth1.exceptions.auth_plugins.NoMatchingPlugin as e:
raise OpenStackCloudException( raise OpenStackCloudException(
"Invalid cloud configuration: {exc}".format(exc=str(e))) "Invalid cloud configuration: {exc}".format(exc=str(e)))
return OpenStackCloud(cloud_config=cloud_region, strict=strict) return connection.Connection(config=cloud_region, strict=strict)

@ -518,8 +518,8 @@ class Normalizer(object):
ret['config_drive'] = config_drive ret['config_drive'] = config_drive
ret['project_id'] = project_id ret['project_id'] = project_id
ret['tenant_id'] = project_id ret['tenant_id'] = project_id
ret['region'] = self.region_name ret['region'] = self.config.region_name
ret['cloud'] = self.name ret['cloud'] = self.config.name
ret['az'] = az ret['az'] = az
for key, val in ret['properties'].items(): for key, val in ret['properties'].items():
ret.setdefault(key, val) ret.setdefault(key, val)

@ -14,8 +14,9 @@
import functools import functools
import openstack.config from openstack.config import loader
import openstack.cloud from openstack import connection
from openstack import exceptions
from openstack.cloud import _utils from openstack.cloud import _utils
@ -30,24 +31,20 @@ class OpenStackInventory(object):
use_direct_get=False): use_direct_get=False):
if config_files is None: if config_files is None:
config_files = [] config_files = []
config = openstack.config.loader.OpenStackConfig( config = loader.OpenStackConfig(
config_files=openstack.config.loader.CONFIG_FILES + config_files) config_files=loader.CONFIG_FILES + config_files)
self.extra_config = config.get_extra_config( self.extra_config = config.get_extra_config(
config_key, config_defaults) config_key, config_defaults)
if cloud is None: if cloud is None:
self.clouds = [ self.clouds = [
openstack.cloud.OpenStackCloud(cloud_config=cloud_region) connection.Connection(config=cloud_region)
for cloud_region in config.get_all() for cloud_region in config.get_all()
] ]
else: else:
try:
self.clouds = [ self.clouds = [
openstack.cloud.OpenStackCloud( connection.Connection(config=config.get_one(cloud))
cloud_config=config.get_one(cloud))
] ]
except openstack.config.exceptions.OpenStackConfigException as e:
raise openstack.cloud.OpenStackCloudException(e)
if private: if private:
for cloud in self.clouds: for cloud in self.clouds:
@ -66,7 +63,7 @@ class OpenStackInventory(object):
# Cycle on servers # Cycle on servers
for server in cloud.list_servers(detailed=expand): for server in cloud.list_servers(detailed=expand):
hostvars.append(server) hostvars.append(server)
except openstack.cloud.OpenStackCloudException: except exceptions.OpenStackCloudException:
# Don't fail on one particular cloud as others may work # Don't fail on one particular cloud as others may work
if fail_on_cloud_config: if fail_on_cloud_config:
raise raise

@ -317,7 +317,7 @@ def _get_interface_ip(cloud, server):
def get_groups_from_server(cloud, server, server_vars): def get_groups_from_server(cloud, server, server_vars):
groups = [] groups = []
region = cloud.region_name region = cloud.config.region_name
cloud_name = cloud.name cloud_name = cloud.name
# Create a group for the cloud # Create a group for the cloud

@ -39,7 +39,6 @@ from six.moves import urllib
import keystoneauth1.exceptions import keystoneauth1.exceptions
import keystoneauth1.session import keystoneauth1.session
from openstack import version as openstack_version
from openstack import _adapter from openstack import _adapter
from openstack import _log from openstack import _log
from openstack.cloud.exc import * # noqa from openstack.cloud.exc import * # noqa
@ -118,65 +117,30 @@ class OpenStackCloud(_normalize.Normalizer):
and that Floating IP will be actualized either via neutron or via nova and that Floating IP will be actualized either via neutron or via nova
depending on how this particular cloud has decided to arrange itself. depending on how this particular cloud has decided to arrange itself.
:param TaskManager manager: Optional task manager to use for running
OpenStack API tasks. Unless you're doing
rate limiting client side, you almost
certainly don't need this. (optional)
:param bool strict: Only return documented attributes for each resource :param bool strict: Only return documented attributes for each resource
as per the Data Model contract. (Default False) as per the Data Model contract. (Default False)
:param app_name: Name of the application to be appended to the user-agent
string. Optional, defaults to None.
:param app_version: Version of the application to be appended to the
user-agent string. Optional, defaults to None.
:param CloudRegion cloud_config: Cloud config object from os-client-config
In the future, this will be the only way
to pass in cloud configuration, but is
being phased in currently.
""" """
def __init__( def __init__(self):
self,
cloud_config=None,
manager=None,
strict=False,
app_name=None,
app_version=None,
use_direct_get=False,
conn=None,
**kwargs):
self.log = _log.setup_logging('openstack') self.log = _log.setup_logging('openstack')
if not cloud_config: self.name = self.config.name
config = openstack.config.OpenStackConfig( self.auth = self.config.get_auth_args()
app_name=app_name, app_version=app_version) self.default_interface = self.config.get_interface()
self.private = self.config.config.get('private', False)
self.image_api_use_tasks = self.config.config['image_api_use_tasks']
self.secgroup_source = self.config.config['secgroup_source']
self.force_ipv4 = self.config.force_ipv4
cloud_config = config.get_one(**kwargs) self._external_ipv4_names = self.config.get_external_ipv4_networks()
self._internal_ipv4_names = self.config.get_internal_ipv4_networks()
self._external_ipv6_names = self.config.get_external_ipv6_networks()
self._internal_ipv6_names = self.config.get_internal_ipv6_networks()
self._nat_destination = self.config.get_nat_destination()
self._default_network = self.config.get_default_network()
self.name = cloud_config.name self._floating_ip_source = self.config.config.get(
self.auth = cloud_config.get_auth_args()
self.region_name = cloud_config.region_name
self.default_interface = cloud_config.get_interface()
self.private = cloud_config.config.get('private', False)
self.image_api_use_tasks = cloud_config.config['image_api_use_tasks']
self.secgroup_source = cloud_config.config['secgroup_source']
self.force_ipv4 = cloud_config.force_ipv4
self.strict_mode = strict
if manager is not None:
self.manager = manager
else:
self.manager = task_manager.TaskManager(
name=':'.join([self.name, self.region_name]))
self._external_ipv4_names = cloud_config.get_external_ipv4_networks()
self._internal_ipv4_names = cloud_config.get_internal_ipv4_networks()
self._external_ipv6_names = cloud_config.get_external_ipv6_networks()
self._internal_ipv6_names = cloud_config.get_internal_ipv6_networks()
self._nat_destination = cloud_config.get_nat_destination()
self._default_network = cloud_config.get_default_network()
self._floating_ip_source = cloud_config.config.get(
'floating_ip_source') 'floating_ip_source')
if self._floating_ip_source: if self._floating_ip_source:
if self._floating_ip_source.lower() == 'none': if self._floating_ip_source.lower() == 'none':
@ -184,16 +148,12 @@ class OpenStackCloud(_normalize.Normalizer):
else: else:
self._floating_ip_source = self._floating_ip_source.lower() self._floating_ip_source = self._floating_ip_source.lower()
self._use_external_network = cloud_config.config.get( self._use_external_network = self.config.config.get(
'use_external_network', True) 'use_external_network', True)
self._use_internal_network = cloud_config.config.get( self._use_internal_network = self.config.config.get(
'use_internal_network', True) 'use_internal_network', True)
# Work around older TaskManager objects that don't have submit_task (self.verify, self.cert) = self.config.get_requests_verify_args()
if not hasattr(self.manager, 'submit_task'):
self.manager.submit_task = self.manager.submitTask
(self.verify, self.cert) = cloud_config.get_requests_verify_args()
# Turn off urllib3 warnings about insecure certs if we have # Turn off urllib3 warnings about insecure certs if we have
# explicitly configured requests to tell it we do not want # explicitly configured requests to tell it we do not want
# cert verification # cert verification
@ -206,7 +166,6 @@ class OpenStackCloud(_normalize.Normalizer):
warnings.filterwarnings('ignore', category=category) warnings.filterwarnings('ignore', category=category)
self._disable_warnings = {} self._disable_warnings = {}
self.use_direct_get = use_direct_get
self._servers = None self._servers = None
self._servers_time = 0 self._servers_time = 0
@ -227,9 +186,9 @@ class OpenStackCloud(_normalize.Normalizer):
self._networks_lock = threading.Lock() self._networks_lock = threading.Lock()
self._reset_network_caches() self._reset_network_caches()
cache_expiration_time = int(cloud_config.get_cache_expiration_time()) cache_expiration_time = int(self.config.get_cache_expiration_time())
cache_class = cloud_config.get_cache_class() cache_class = self.config.get_cache_class()
cache_arguments = cloud_config.get_cache_arguments() cache_arguments = self.config.get_cache_arguments()
self._resource_caches = {} self._resource_caches = {}
@ -237,7 +196,7 @@ class OpenStackCloud(_normalize.Normalizer):
self.cache_enabled = True self.cache_enabled = True
self._cache = self._make_cache( self._cache = self._make_cache(
cache_class, cache_expiration_time, cache_arguments) cache_class, cache_expiration_time, cache_arguments)
expirations = cloud_config.get_cache_expiration() expirations = self.config.get_cache_expiration()
for expire_key in expirations.keys(): for expire_key in expirations.keys():
# Only build caches for things we have list operations for # Only build caches for things we have list operations for
if getattr( if getattr(
@ -279,36 +238,21 @@ class OpenStackCloud(_normalize.Normalizer):
# If server expiration time is set explicitly, use that. Otherwise # If server expiration time is set explicitly, use that. Otherwise
# fall back to whatever it was before # fall back to whatever it was before
self._SERVER_AGE = cloud_config.get_cache_resource_expiration( self._SERVER_AGE = self.config.get_cache_resource_expiration(
'server', self._SERVER_AGE) 'server', self._SERVER_AGE)
self._PORT_AGE = cloud_config.get_cache_resource_expiration( self._PORT_AGE = self.config.get_cache_resource_expiration(
'port', self._PORT_AGE) 'port', self._PORT_AGE)
self._FLOAT_AGE = cloud_config.get_cache_resource_expiration( self._FLOAT_AGE = self.config.get_cache_resource_expiration(
'floating_ip', self._FLOAT_AGE) 'floating_ip', self._FLOAT_AGE)
self._container_cache = dict() self._container_cache = dict()
self._file_hash_cache = dict() self._file_hash_cache = dict()
self._keystone_session = None
self._raw_clients = {} self._raw_clients = {}
self._local_ipv6 = ( self._local_ipv6 = (
_utils.localhost_supports_ipv6() if not self.force_ipv4 else False) _utils.localhost_supports_ipv6() if not self.force_ipv4 else False)
self.cloud_config = cloud_config
self._conn_object = conn
@property
def _conn(self):
if not self._conn_object:
# Importing late to avoid import cycle. If the OpenStackCloud
# object comes via Connection, it'll have connection passed in.
import openstack.connection
self._conn_object = openstack.connection.Connection(
config=self.cloud_config, session=self._keystone_session)
return self._conn_object
def connect_as(self, **kwargs): def connect_as(self, **kwargs):
"""Make a new OpenStackCloud object with new auth context. """Make a new OpenStackCloud object with new auth context.
@ -332,11 +276,12 @@ class OpenStackCloud(_normalize.Normalizer):
that do not want to be overridden can be ommitted. that do not want to be overridden can be ommitted.
""" """
# TODO(mordred) Replace this with from_session
config = openstack.config.OpenStackConfig( config = openstack.config.OpenStackConfig(
app_name=self.cloud_config._app_name, app_name=self.config._app_name,
app_version=self.cloud_config._app_version, app_version=self.config._app_version,
load_yaml_config=False) load_yaml_config=False)
params = copy.deepcopy(self.cloud_config.config) params = copy.deepcopy(self.config.config)
# Remove profile from current cloud so that overridding works # Remove profile from current cloud so that overridding works
params.pop('profile', None) params.pop('profile', None)
@ -373,7 +318,7 @@ class OpenStackCloud(_normalize.Normalizer):
def session_constructor(*args, **kwargs): def session_constructor(*args, **kwargs):
# We need to pass our current keystone session to the Session # We need to pass our current keystone session to the Session
# Constructor, otherwise the new auth plugin doesn't get used. # Constructor, otherwise the new auth plugin doesn't get used.
return keystoneauth1.session.Session(session=self.keystone_session) return keystoneauth1.session.Session(session=self.session)
# Use cloud='defaults' so that we overlay settings properly # Use cloud='defaults' so that we overlay settings properly
cloud_config = config.get_one( cloud_config = config.get_one(
@ -385,7 +330,7 @@ class OpenStackCloud(_normalize.Normalizer):
cloud_config.config['profile'] = self.name cloud_config.config['profile'] = self.name
# Use self.__class__ so that we return whatever this if, like if it's # Use self.__class__ so that we return whatever this if, like if it's
# a subclass in the case of shade wrapping sdk. # a subclass in the case of shade wrapping sdk.
return self.__class__(cloud_config=cloud_config) return self.__class__(config=cloud_config)
def connect_as_project(self, project): def connect_as_project(self, project):
"""Make a new OpenStackCloud object with a new project. """Make a new OpenStackCloud object with a new project.
@ -457,7 +402,7 @@ class OpenStackCloud(_normalize.Normalizer):
def _get_versioned_client( def _get_versioned_client(
self, service_type, min_version=None, max_version=None): self, service_type, min_version=None, max_version=None):
config_version = self.cloud_config.get_api_version(service_type) config_version = self.config.get_api_version(service_type)
config_major = self._get_major_version_id(config_version) config_major = self._get_major_version_id(config_version)
max_major = self._get_major_version_id(max_version) max_major = self._get_major_version_id(max_version)
min_major = self._get_major_version_id(min_version) min_major = self._get_major_version_id(min_version)
@ -492,33 +437,33 @@ class OpenStackCloud(_normalize.Normalizer):
request_max_version = '{version}.latest'.format( request_max_version = '{version}.latest'.format(
version=config_major) version=config_major)
adapter = _adapter.ShadeAdapter( adapter = _adapter.ShadeAdapter(
session=self.keystone_session, session=self.session,
task_manager=self.manager, task_manager=self.task_manager,
service_type=self.cloud_config.get_service_type(service_type), service_type=self.config.get_service_type(service_type),
service_name=self.cloud_config.get_service_name(service_type), service_name=self.config.get_service_name(service_type),
interface=self.cloud_config.get_interface(service_type), interface=self.config.get_interface(service_type),
endpoint_override=self.cloud_config.get_endpoint(service_type), endpoint_override=self.config.get_endpoint(service_type),
region_name=self.cloud_config.region_name, region_name=self.config.region_name,
min_version=request_min_version, min_version=request_min_version,
max_version=request_max_version) max_version=request_max_version)
if adapter.get_endpoint(): if adapter.get_endpoint():
return adapter return adapter
adapter = _adapter.ShadeAdapter( adapter = _adapter.ShadeAdapter(
session=self.keystone_session, session=self.session,
task_manager=self.manager, task_manager=self.task_manager,
service_type=self.cloud_config.get_service_type(service_type), service_type=self.config.get_service_type(service_type),
service_name=self.cloud_config.get_service_name(service_type), service_name=self.config.get_service_name(service_type),
interface=self.cloud_config.get_interface(service_type), interface=self.config.get_interface(service_type),
endpoint_override=self.cloud_config.get_endpoint(service_type), endpoint_override=self.config.get_endpoint(service_type),
region_name=self.cloud_config.region_name, region_name=self.config.region_name,
min_version=min_version, min_version=min_version,
max_version=max_version) max_version=max_version)
# data.api_version can be None if no version was detected, such # data.api_version can be None if no version was detected, such
# as with neutron # as with neutron
api_version = adapter.get_api_major_version( api_version = adapter.get_api_major_version(
endpoint_override=self.cloud_config.get_endpoint(service_type)) endpoint_override=self.config.get_endpoint(service_type))
api_major = self._get_major_version_id(api_version) api_major = self._get_major_version_id(api_version)
# If we detect a different version that was configured, warn the user. # If we detect a different version that was configured, warn the user.
@ -544,14 +489,14 @@ class OpenStackCloud(_normalize.Normalizer):
def _get_raw_client( def _get_raw_client(
self, service_type, api_version=None, endpoint_override=None): self, service_type, api_version=None, endpoint_override=None):
return _adapter.ShadeAdapter( return _adapter.ShadeAdapter(
session=self.keystone_session, session=self.session,
task_manager=self.manager, task_manager=self.task_manager,
service_type=self.cloud_config.get_service_type(service_type), service_type=self.config.get_service_type(service_type),
service_name=self.cloud_config.get_service_name(service_type), service_name=self.config.get_service_name(service_type),
interface=self.cloud_config.get_interface(service_type), interface=self.config.get_interface(service_type),
endpoint_override=self.cloud_config.get_endpoint( endpoint_override=self.config.get_endpoint(
service_type) or endpoint_override, service_type) or endpoint_override,
region_name=self.cloud_config.region_name) region_name=self.config.region_name)
def _is_client_version(self, client, version): def _is_client_version(self, client, version):
client_name = '_{client}_client'.format(client=client) client_name = '_{client}_client'.format(client=client)
@ -673,23 +618,9 @@ class OpenStackCloud(_normalize.Normalizer):
new_resource = _utils._dictify_resource(resource) new_resource = _utils._dictify_resource(resource)
return pprint.pformat(new_resource) return pprint.pformat(new_resource)
@property
def keystone_session(self):
if self._keystone_session is None:
try:
self._keystone_session = self.cloud_config.get_session()
if hasattr(self._keystone_session, 'additional_user_agent'):
self._keystone_session.additional_user_agent.append(
('openstacksdk', openstack_version.__version__))
except Exception as e:
raise OpenStackCloudException(
"Error authenticating to keystone: %s " % str(e))
return self._keystone_session
@property @property
def _keystone_catalog(self): def _keystone_catalog(self):
return self.keystone_session.auth.get_access( return self.session.auth.get_access(self.session).service_catalog
self.keystone_session).service_catalog
@property @property
def service_catalog(self): def service_catalog(self):
@ -703,13 +634,12 @@ class OpenStackCloud(_normalize.Normalizer):
def auth_token(self): def auth_token(self):
# Keystone's session will reuse a token if it is still valid. # Keystone's session will reuse a token if it is still valid.
# We don't need to track validity here, just get_token() each time. # We don't need to track validity here, just get_token() each time.
return self.keystone_session.get_token() return self.session.get_token()
@property @property
def current_user_id(self): def current_user_id(self):
"""Get the id of the currently logged-in user from the token.""" """Get the id of the currently logged-in user from the token."""
return self.keystone_session.auth.get_access( return self.session.auth.get_access(self.session).user_id
self.keystone_session).user_id
@property @property
def current_project_id(self): def current_project_id(self):
@ -723,7 +653,7 @@ class OpenStackCloud(_normalize.Normalizer):
:raises keystoneauth1.exceptions.auth_plugins.MissingAuthPlugin: :raises keystoneauth1.exceptions.auth_plugins.MissingAuthPlugin:
if a plugin is not available. if a plugin is not available.
""" """
return self.keystone_session.get_project_id() return self.session.get_project_id()
@property @property
def current_project(self): def current_project(self):
@ -748,7 +678,7 @@ class OpenStackCloud(_normalize.Normalizer):
# If they don't match, that means we're an admin who has pulled # If they don't match, that means we're an admin who has pulled
# an object from a different project, so adding info from the # an object from a different project, so adding info from the
# current token would be wrong. # current token would be wrong.
auth_args = self.cloud_config.config.get('auth', {}) auth_args = self.config.config.get('auth', {})
project_info['id'] = self.current_project_id project_info['id'] = self.current_project_id
project_info['name'] = auth_args.get('project_name') project_info['name'] = auth_args.get('project_name')
project_info['domain_id'] = auth_args.get('project_domain_id') project_info['domain_id'] = auth_args.get('project_domain_id')
@ -763,7 +693,7 @@ class OpenStackCloud(_normalize.Normalizer):
def _get_current_location(self, project_id=None, zone=None): def _get_current_location(self, project_id=None, zone=None):
return munch.Munch( return munch.Munch(
cloud=self.name, cloud=self.name,
region_name=self.region_name, region_name=self.config.region_name,
zone=zone, zone=zone,
project=self._get_project_info(project_id), project=self._get_project_info(project_id),
) )
@ -1419,7 +1349,7 @@ class OpenStackCloud(_normalize.Normalizer):
return self.name return self.name
def get_region(self): def get_region(self):
return self.region_name return self.config.region_name
def get_flavor_name(self, flavor_id): def get_flavor_name(self, flavor_id):
flavor = self.get_flavor(flavor_id, get_extra=False) flavor = self.get_flavor(flavor_id, get_extra=False)
@ -1449,7 +1379,7 @@ class OpenStackCloud(_normalize.Normalizer):
def get_session_endpoint(self, service_key): def get_session_endpoint(self, service_key):
try: try:
return self.cloud_config.get_session_endpoint(service_key) return self.config.get_session_endpoint(service_key)
except keystoneauth1.exceptions.catalog.EndpointNotFound as e: except keystoneauth1.exceptions.catalog.EndpointNotFound as e:
self.log.debug( self.log.debug(
"Endpoint not found in %s cloud: %s", self.name, str(e)) "Endpoint not found in %s cloud: %s", self.name, str(e))
@ -1462,12 +1392,12 @@ class OpenStackCloud(_normalize.Normalizer):
" {error}".format( " {error}".format(
service=service_key, service=service_key,
cloud=self.name, cloud=self.name,
region=self.region_name, region=self.config.region_name,
error=str(e))) error=str(e)))
return endpoint return endpoint
def has_service(self, service_key): def has_service(self, service_key):
if not self.cloud_config.config.get('has_%s' % service_key, True): if not self.config.config.get('has_%s' % service_key, True):
# TODO(mordred) add a stamp here so that we only report this once # TODO(mordred) add a stamp here so that we only report this once
if not (service_key in self._disable_warnings if not (service_key in self._disable_warnings
and self._disable_warnings[service_key]): and self._disable_warnings[service_key]):
@ -1489,7 +1419,7 @@ class OpenStackCloud(_normalize.Normalizer):
def _nova_extensions(self): def _nova_extensions(self):
extensions = set() extensions = set()
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('/extensions'), self.compute.get('/extensions'),
error_message="Error fetching extension list for nova") error_message="Error fetching extension list for nova")
for extension in self._get_and_munchify('extensions', data): for extension in self._get_and_munchify('extensions', data):
@ -1694,7 +1624,7 @@ class OpenStackCloud(_normalize.Normalizer):
""" """
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('/os-keypairs'), self.compute.get('/os-keypairs'),
error_message="Error fetching keypair list") error_message="Error fetching keypair list")
return self._normalize_keypairs([ return self._normalize_keypairs([
k['keypair'] for k in self._get_and_munchify('keypairs', data)]) k['keypair'] for k in self._get_and_munchify('keypairs', data)])
@ -1921,7 +1851,7 @@ class OpenStackCloud(_normalize.Normalizer):
""" """
try: try:
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('/os-availability-zone')) self.compute.get('/os-availability-zone'))
except OpenStackCloudHTTPError: except OpenStackCloudHTTPError:
self.log.debug( self.log.debug(
"Availability zone list could not be fetched", "Availability zone list could not be fetched",
@ -1946,7 +1876,7 @@ class OpenStackCloud(_normalize.Normalizer):
""" """
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get( self.compute.get(
'/flavors/detail', params=dict(is_public='None')), '/flavors/detail', params=dict(is_public='None')),
error_message="Error fetching flavor list") error_message="Error fetching flavor list")
flavors = self._normalize_flavors( flavors = self._normalize_flavors(
@ -1958,7 +1888,7 @@ class OpenStackCloud(_normalize.Normalizer):
id=flavor.id) id=flavor.id)
try: try:
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get(endpoint), self.compute.get(endpoint),
error_message="Error fetching flavor extra specs") error_message="Error fetching flavor extra specs")
flavor.extra_specs = self._get_and_munchify( flavor.extra_specs = self._get_and_munchify(
'extra_specs', data) 'extra_specs', data)
@ -1995,7 +1925,7 @@ class OpenStackCloud(_normalize.Normalizer):
return [] return []
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get( self.compute.get(
'/servers/{server_id}/os-security-groups'.format( '/servers/{server_id}/os-security-groups'.format(
server_id=server['id']))) server_id=server['id'])))
return self._normalize_secgroups( return self._normalize_secgroups(
@ -2051,7 +1981,7 @@ class OpenStackCloud(_normalize.Normalizer):
return False return False
for sg in security_groups: for sg in security_groups:
_adapter._json_response(self._conn.compute.post( _adapter._json_response(self.compute.post(
'/servers/%s/action' % server['id'], '/servers/%s/action' % server['id'],
json={'addSecurityGroup': {'name': sg.name}})) json={'addSecurityGroup': {'name': sg.name}}))
@ -2079,7 +2009,7 @@ class OpenStackCloud(_normalize.Normalizer):
for sg in security_groups: for sg in security_groups:
try: try:
_adapter._json_response(self._conn.compute.post( _adapter._json_response(self.compute.post(
'/servers/%s/action' % server['id'], '/servers/%s/action' % server['id'],
json={'removeSecurityGroup': {'name': sg.name}})) json={'removeSecurityGroup': {'name': sg.name}}))
@ -2121,7 +2051,7 @@ class OpenStackCloud(_normalize.Normalizer):
# Handle nova security groups # Handle nova security groups
else: else:
data = _adapter._json_response(self._conn.compute.get( data = _adapter._json_response(self.compute.get(
'/os-security-groups', params=filters)) '/os-security-groups', params=filters))
return self._normalize_secgroups( return self._normalize_secgroups(
self._get_and_munchify('security_groups', data)) self._get_and_munchify('security_groups', data))
@ -2169,13 +2099,13 @@ class OpenStackCloud(_normalize.Normalizer):
filters=None): filters=None):
error_msg = "Error fetching server list on {cloud}:{region}:".format( error_msg = "Error fetching server list on {cloud}:{region}:".format(
cloud=self.name, cloud=self.name,
region=self.region_name) region=self.config.region_name)
params = filters or {} params = filters or {}
if all_projects: if all_projects:
params['all_tenants'] = True params['all_tenants'] = True
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get( self.compute.get(
'/servers/detail', params=params), '/servers/detail', params=params),
error_message=error_msg) error_message=error_msg)
servers = self._normalize_servers( servers = self._normalize_servers(
@ -2192,7 +2122,7 @@ class OpenStackCloud(_normalize.Normalizer):
""" """
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('/os-server-groups'), self.compute.get('/os-server-groups'),
error_message="Error fetching server group list") error_message="Error fetching server group list")
return self._get_and_munchify('server_groups', data) return self._get_and_munchify('server_groups', data)
@ -2219,7 +2149,7 @@ class OpenStackCloud(_normalize.Normalizer):
msg=error_msg, project=name_or_id) msg=error_msg, project=name_or_id)
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('/limits', params=params)) self.compute.get('/limits', params=params))
limits = self._get_and_munchify('limits', data) limits = self._get_and_munchify('limits', data)
return self._normalize_compute_limits(limits, project_id=project_id) return self._normalize_compute_limits(limits, project_id=project_id)
@ -2254,7 +2184,7 @@ class OpenStackCloud(_normalize.Normalizer):
# We didn't have glance, let's try nova # We didn't have glance, let's try nova
# If this doesn't work - we just let the exception propagate # If this doesn't work - we just let the exception propagate
response = _adapter._json_response( response = _adapter._json_response(
self._conn.compute.get('/images/detail')) self.compute.get('/images/detail'))
while 'next' in response: while 'next' in response:
image_list.extend(meta.obj_list_to_munch(response['images'])) image_list.extend(meta.obj_list_to_munch(response['images']))
endpoint = response['next'] endpoint = response['next']
@ -2295,7 +2225,7 @@ class OpenStackCloud(_normalize.Normalizer):
'Floating IP pools extension is not available on target cloud') 'Floating IP pools extension is not available on target cloud')
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('os-floating-ip-pools'), self.compute.get('os-floating-ip-pools'),
error_message="Error fetching floating IP pool list") error_message="Error fetching floating IP pool list")
pools = self._get_and_munchify('floating_ip_pools', data) pools = self._get_and_munchify('floating_ip_pools', data)
return [{'name': p['name']} for p in pools] return [{'name': p['name']} for p in pools]
@ -2386,7 +2316,7 @@ class OpenStackCloud(_normalize.Normalizer):
def _nova_list_floating_ips(self): def _nova_list_floating_ips(self):
try: try:
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('/os-floating-ips')) self.compute.get('/os-floating-ips'))
except OpenStackCloudURINotFound: except OpenStackCloudURINotFound:
return [] return []
return self._get_and_munchify('floating_ips', data) return self._get_and_munchify('floating_ips', data)
@ -2991,7 +2921,7 @@ class OpenStackCloud(_normalize.Normalizer):
:returns: A flavor ``munch.Munch``. :returns: A flavor ``munch.Munch``.
""" """
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('/flavors/{id}'.format(id=id)), self.compute.get('/flavors/{id}'.format(id=id)),
error_message="Error getting flavor with ID {id}".format(id=id) error_message="Error getting flavor with ID {id}".format(id=id)
) )
flavor = self._normalize_flavor( flavor = self._normalize_flavor(
@ -3002,7 +2932,7 @@ class OpenStackCloud(_normalize.Normalizer):
id=flavor.id) id=flavor.id)
try: try:
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get(endpoint), self.compute.get(endpoint),
error_message="Error fetching flavor extra specs") error_message="Error fetching flavor extra specs")
flavor.extra_specs = self._get_and_munchify( flavor.extra_specs = self._get_and_munchify(
'extra_specs', data) 'extra_specs', data)
@ -3058,7 +2988,7 @@ class OpenStackCloud(_normalize.Normalizer):
error_message=error_message) error_message=error_message)
else: else:
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get( self.compute.get(
'/os-security-groups/{id}'.format(id=id)), '/os-security-groups/{id}'.format(id=id)),
error_message=error_message) error_message=error_message)
return self._normalize_secgroup( return self._normalize_secgroup(
@ -3091,7 +3021,7 @@ class OpenStackCloud(_normalize.Normalizer):
return "" return ""
def _get_server_console_output(self, server_id, length=None): def _get_server_console_output(self, server_id, length=None):
data = _adapter._json_response(self._conn.compute.post( data = _adapter._json_response(self.compute.post(
'/servers/{server_id}/action'.format(server_id=server_id), '/servers/{server_id}/action'.format(server_id=server_id),
json={'os-getConsoleOutput': {'length': length}})) json={'os-getConsoleOutput': {'length': length}}))
return self._get_and_munchify('output', data) return self._get_and_munchify('output', data)
@ -3145,7 +3075,7 @@ class OpenStackCloud(_normalize.Normalizer):
def get_server_by_id(self, id): def get_server_by_id(self, id):
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('/servers/{id}'.format(id=id))) self.compute.get('/servers/{id}'.format(id=id)))
server = self._get_and_munchify('server', data) server = self._get_and_munchify('server', data)
return meta.add_server_interfaces(self, self._normalize_server(server)) return meta.add_server_interfaces(self, self._normalize_server(server))
@ -3304,7 +3234,7 @@ class OpenStackCloud(_normalize.Normalizer):
self._get_and_munchify('floatingip', data)) self._get_and_munchify('floatingip', data))
else: else:
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('/os-floating-ips/{id}'.format(id=id)), self.compute.get('/os-floating-ips/{id}'.format(id=id)),
error_message=error_message) error_message=error_message)
return self._normalize_floating_ip( return self._normalize_floating_ip(
self._get_and_munchify('floating_ip', data)) self._get_and_munchify('floating_ip', data))
@ -3355,7 +3285,7 @@ class OpenStackCloud(_normalize.Normalizer):
if public_key: if public_key:
keypair['public_key'] = public_key keypair['public_key'] = public_key
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/os-keypairs', '/os-keypairs',
json={'keypair': keypair}), json={'keypair': keypair}),
error_message="Unable to create keypair {name}".format(name=name)) error_message="Unable to create keypair {name}".format(name=name))
@ -3372,7 +3302,7 @@ class OpenStackCloud(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error. :raises: OpenStackCloudException on operation error.
""" """
try: try:
_adapter._json_response(self._conn.compute.delete( _adapter._json_response(self.compute.delete(
'/os-keypairs/{name}'.format(name=name))) '/os-keypairs/{name}'.format(name=name)))
except OpenStackCloudURINotFound: except OpenStackCloudURINotFound:
self.log.debug("Keypair %s not found for deleting", name) self.log.debug("Keypair %s not found for deleting", name)
@ -4432,7 +4362,7 @@ class OpenStackCloud(_normalize.Normalizer):
" could not be snapshotted.".format(server=server)) " could not be snapshotted.".format(server=server))
server = server_obj server = server_obj
response = _adapter._json_response( response = _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/servers/{server_id}/action'.format(server_id=server['id']), '/servers/{server_id}/action'.format(server_id=server['id']),
json={ json={
"createImage": { "createImage": {
@ -4523,7 +4453,7 @@ class OpenStackCloud(_normalize.Normalizer):
# Try appending the disk format # Try appending the disk format
name_with_ext = '.'.join(( name_with_ext = '.'.join((
name, self.cloud_config.config['image_format'])) name, self.config.config['image_format']))
if os.path.exists(name_with_ext): if os.path.exists(name_with_ext):
return (os.path.basename(name), name_with_ext) return (os.path.basename(name), name_with_ext)
@ -4615,7 +4545,7 @@ class OpenStackCloud(_normalize.Normalizer):
meta = {} meta = {}
if not disk_format: if not disk_format:
disk_format = self.cloud_config.config['image_format'] disk_format = self.config.config['image_format']
if not container_format: if not container_format:
# https://docs.openstack.org/image-guide/image-formats.html # https://docs.openstack.org/image-guide/image-formats.html
container_format = 'bare' container_format = 'bare'
@ -4661,7 +4591,7 @@ class OpenStackCloud(_normalize.Normalizer):
kwargs[IMAGE_OBJECT_KEY] = '/'.join([container, name]) kwargs[IMAGE_OBJECT_KEY] = '/'.join([container, name])
if disable_vendor_agent: if disable_vendor_agent:
kwargs.update(self.cloud_config.config['disable_vendor_agent']) kwargs.update(self.config.config['disable_vendor_agent'])
# We can never have nice things. Glance v1 took "is_public" as a # We can never have nice things. Glance v1 took "is_public" as a
# boolean. Glance v2 takes "visibility". If the user gives us # boolean. Glance v2 takes "visibility". If the user gives us
@ -5169,7 +5099,7 @@ class OpenStackCloud(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error. :raises: OpenStackCloudException on operation error.
""" """
_adapter._json_response(self._conn.compute.delete( _adapter._json_response(self.compute.delete(
'/servers/{server_id}/os-volume_attachments/{volume_id}'.format( '/servers/{server_id}/os-volume_attachments/{volume_id}'.format(
server_id=server['id'], volume_id=volume['id'])), server_id=server['id'], volume_id=volume['id'])),
error_message=( error_message=(
@ -5237,7 +5167,7 @@ class OpenStackCloud(_normalize.Normalizer):
if device: if device:
payload['device'] = device payload['device'] = device
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/servers/{server_id}/os-volume_attachments'.format( '/servers/{server_id}/os-volume_attachments'.format(
server_id=server['id']), server_id=server['id']),
json=dict(volumeAttachment=payload)), json=dict(volumeAttachment=payload)),
@ -5884,12 +5814,12 @@ class OpenStackCloud(_normalize.Normalizer):
"unable to find a floating ip pool") "unable to find a floating ip pool")
pool = pools[0]['name'] pool = pools[0]['name']
data = _adapter._json_response(self._conn.compute.post( data = _adapter._json_response(self.compute.post(
'/os-floating-ips', json=dict(pool=pool))) '/os-floating-ips', json=dict(pool=pool)))
pool_ip = self._get_and_munchify('floating_ip', data) pool_ip = self._get_and_munchify('floating_ip', data)
# TODO(mordred) Remove this - it's just for compat # TODO(mordred) Remove this - it's just for compat
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('/os-floating-ips/{id}'.format( self.compute.get('/os-floating-ips/{id}'.format(
id=pool_ip['id']))) id=pool_ip['id'])))
return self._get_and_munchify('floating_ip', data) return self._get_and_munchify('floating_ip', data)
@ -5959,7 +5889,7 @@ class OpenStackCloud(_normalize.Normalizer):
def _nova_delete_floating_ip(self, floating_ip_id): def _nova_delete_floating_ip(self, floating_ip_id):
try: try:
_adapter._json_response( _adapter._json_response(
self._conn.compute.delete( self.compute.delete(
'/os-floating-ips/{id}'.format(id=floating_ip_id)), '/os-floating-ips/{id}'.format(id=floating_ip_id)),
error_message='Unable to delete floating IP {fip_id}'.format( error_message='Unable to delete floating IP {fip_id}'.format(
fip_id=floating_ip_id)) fip_id=floating_ip_id))
@ -6209,7 +6139,7 @@ class OpenStackCloud(_normalize.Normalizer):
if fixed_address: if fixed_address:
body['fixed_address'] = fixed_address body['fixed_address'] = fixed_address
return _adapter._json_response( return _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/servers/{server_id}/action'.format(server_id=server_id), '/servers/{server_id}/action'.format(server_id=server_id),
json=dict(addFloatingIp=body)), json=dict(addFloatingIp=body)),
error_message=error_message) error_message=error_message)
@ -6261,7 +6191,7 @@ class OpenStackCloud(_normalize.Normalizer):
error_message = "Error detaching IP {ip} from instance {id}".format( error_message = "Error detaching IP {ip} from instance {id}".format(
ip=floating_ip_id, id=server_id) ip=floating_ip_id, id=server_id)
return _adapter._json_response( return _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/servers/{server_id}/action'.format(server_id=server_id), '/servers/{server_id}/action'.format(server_id=server_id),
json=dict(removeFloatingIp=dict( json=dict(removeFloatingIp=dict(
address=f_ip['floating_ip_address']))), address=f_ip['floating_ip_address']))),
@ -6512,7 +6442,7 @@ class OpenStackCloud(_normalize.Normalizer):
'Volume {boot_volume} is not a valid volume' 'Volume {boot_volume} is not a valid volume'
' in {cloud}:{region}'.format( ' in {cloud}:{region}'.format(
boot_volume=boot_volume, boot_volume=boot_volume,
cloud=self.name, region=self.region_name)) cloud=self.name, region=self.config.region_name))
block_mapping = { block_mapping = {
'boot_index': '0', 'boot_index': '0',
'delete_on_termination': terminate_volume, 'delete_on_termination': terminate_volume,
@ -6533,7 +6463,7 @@ class OpenStackCloud(_normalize.Normalizer):
'Image {image} is not a valid image in' 'Image {image} is not a valid image in'
' {cloud}:{region}'.format( ' {cloud}:{region}'.format(
image=image, image=image,
cloud=self.name, region=self.region_name)) cloud=self.name, region=self.config.region_name))
block_mapping = { block_mapping = {
'boot_index': '0', 'boot_index': '0',
@ -6563,7 +6493,7 @@ class OpenStackCloud(_normalize.Normalizer):
'Volume {volume} is not a valid volume' 'Volume {volume} is not a valid volume'
' in {cloud}:{region}'.format( ' in {cloud}:{region}'.format(
volume=volume, volume=volume,
cloud=self.name, region=self.region_name)) cloud=self.name, region=self.config.region_name))
block_mapping = { block_mapping = {
'boot_index': '-1', 'boot_index': '-1',
'delete_on_termination': False, 'delete_on_termination': False,
@ -6757,7 +6687,7 @@ class OpenStackCloud(_normalize.Normalizer):
'Network {network} is not a valid network in' 'Network {network} is not a valid network in'
' {cloud}:{region}'.format( ' {cloud}:{region}'.format(
network=network, network=network,
cloud=self.name, region=self.region_name)) cloud=self.name, region=self.config.region_name))
nics.append({'net-id': network_obj['id']}) nics.append({'net-id': network_obj['id']})
kwargs['nics'] = nics kwargs['nics'] = nics
@ -6827,7 +6757,7 @@ class OpenStackCloud(_normalize.Normalizer):
endpoint = '/os-volumes_boot' endpoint = '/os-volumes_boot'
with _utils.shade_exceptions("Error in creating instance"): with _utils.shade_exceptions("Error in creating instance"):
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.post(endpoint, json={'server': kwargs})) self.compute.post(endpoint, json={'server': kwargs}))
server = self._get_and_munchify('server', data) server = self._get_and_munchify('server', data)
admin_pass = server.get('adminPass') or kwargs.get('admin_pass') admin_pass = server.get('adminPass') or kwargs.get('admin_pass')
if not wait: if not wait:
@ -6947,7 +6877,7 @@ class OpenStackCloud(_normalize.Normalizer):
kwargs['adminPass'] = admin_pass kwargs['adminPass'] = admin_pass
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/servers/{server_id}/action'.format(server_id=server_id), '/servers/{server_id}/action'.format(server_id=server_id),
json={'rebuild': kwargs}), json={'rebuild': kwargs}),
error_message="Error in rebuilding instance") error_message="Error in rebuilding instance")
@ -6997,7 +6927,7 @@ class OpenStackCloud(_normalize.Normalizer):
'Invalid Server {server}'.format(server=name_or_id)) 'Invalid Server {server}'.format(server=name_or_id))
_adapter._json_response( _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/servers/{server_id}/metadata'.format(server_id=server['id']), '/servers/{server_id}/metadata'.format(server_id=server['id']),
json={'metadata': metadata}), json={'metadata': metadata}),
error_message='Error updating server metadata') error_message='Error updating server metadata')
@ -7021,7 +6951,7 @@ class OpenStackCloud(_normalize.Normalizer):
error_message = 'Error deleting metadata {key} on {server}'.format( error_message = 'Error deleting metadata {key} on {server}'.format(
key=key, server=name_or_id) key=key, server=name_or_id)
_adapter._json_response( _adapter._json_response(
self._conn.compute.delete( self.compute.delete(
'/servers/{server_id}/metadata/{key}'.format( '/servers/{server_id}/metadata/{key}'.format(
server_id=server['id'], server_id=server['id'],
key=key)), key=key)),
@ -7095,7 +7025,7 @@ class OpenStackCloud(_normalize.Normalizer):
try: try:
_adapter._json_response( _adapter._json_response(
self._conn.compute.delete( self.compute.delete(
'/servers/{id}'.format(id=server['id'])), '/servers/{id}'.format(id=server['id'])),
error_message="Error in deleting server") error_message="Error in deleting server")
except OpenStackCloudURINotFound: except OpenStackCloudURINotFound:
@ -7160,7 +7090,7 @@ class OpenStackCloud(_normalize.Normalizer):
"failed to find server '{server}'".format(server=name_or_id)) "failed to find server '{server}'".format(server=name_or_id))
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.put( self.compute.put(
'/servers/{server_id}'.format(server_id=server['id']), '/servers/{server_id}'.format(server_id=server['id']),
json={'server': kwargs}), json={'server': kwargs}),
error_message="Error updating server {0}".format(name_or_id)) error_message="Error updating server {0}".format(name_or_id))
@ -7179,7 +7109,7 @@ class OpenStackCloud(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error. :raises: OpenStackCloudException on operation error.
""" """
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/os-server-groups', '/os-server-groups',
json={ json={
'server_group': { 'server_group': {
@ -7205,7 +7135,7 @@ class OpenStackCloud(_normalize.Normalizer):
return False return False
_adapter._json_response( _adapter._json_response(
self._conn.compute.delete( self.compute.delete(
'/os-server-groups/{id}'.format(id=server_group['id'])), '/os-server-groups/{id}'.format(id=server_group['id'])),
error_message="Error deleting server group {name}".format( error_message="Error deleting server group {name}".format(
name=name_or_id)) name=name_or_id))
@ -8149,7 +8079,7 @@ class OpenStackCloud(_normalize.Normalizer):
json=security_group_json, json=security_group_json,
error_message="Error creating security group {0}".format(name)) error_message="Error creating security group {0}".format(name))
else: else:
data = _adapter._json_response(self._conn.compute.post( data = _adapter._json_response(self.compute.post(
'/os-security-groups', json=security_group_json)) '/os-security-groups', json=security_group_json))
return self._normalize_secgroup( return self._normalize_secgroup(
self._get_and_munchify('security_group', data)) self._get_and_munchify('security_group', data))
@ -8188,7 +8118,7 @@ class OpenStackCloud(_normalize.Normalizer):
return True return True
else: else:
_adapter._json_response(self._conn.compute.delete( _adapter._json_response(self.compute.delete(
'/os-security-groups/{id}'.format(id=secgroup['id']))) '/os-security-groups/{id}'.format(id=secgroup['id'])))
return True return True
@ -8226,7 +8156,7 @@ class OpenStackCloud(_normalize.Normalizer):
for key in ('name', 'description'): for key in ('name', 'description'):
kwargs.setdefault(key, group[key]) kwargs.setdefault(key, group[key])
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.put( self.compute.put(
'/os-security-groups/{id}'.format(id=group['id']), '/os-security-groups/{id}'.format(id=group['id']),
json={'security-group': kwargs})) json={'security-group': kwargs}))
return self._normalize_secgroup( return self._normalize_secgroup(
@ -8361,7 +8291,7 @@ class OpenStackCloud(_normalize.Normalizer):
security_group_rule_dict[ security_group_rule_dict[
'security_group_rule']['tenant_id'] = project_id 'security_group_rule']['tenant_id'] = project_id
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/os-security-group-rules', '/os-security-group-rules',
json=security_group_rule_dict json=security_group_rule_dict
)) ))
@ -8396,7 +8326,7 @@ class OpenStackCloud(_normalize.Normalizer):
return True return True
else: else:
_adapter._json_response(self._conn.compute.delete( _adapter._json_response(self.compute.delete(
'/os-security-group-rules/{id}'.format(id=rule_id))) '/os-security-group-rules/{id}'.format(id=rule_id)))
return True return True
@ -10509,7 +10439,7 @@ class OpenStackCloud(_normalize.Normalizer):
} }
if flavorid == 'auto': if flavorid == 'auto':
payload['id'] = None payload['id'] = None
data = _adapter._json_response(self._conn.compute.post( data = _adapter._json_response(self.compute.post(
'/flavors', '/flavors',
json=dict(flavor=payload))) json=dict(flavor=payload)))
@ -10532,7 +10462,7 @@ class OpenStackCloud(_normalize.Normalizer):
return False return False
_adapter._json_response( _adapter._json_response(
self._conn.compute.delete( self.compute.delete(
'/flavors/{id}'.format(id=flavor['id'])), '/flavors/{id}'.format(id=flavor['id'])),
error_message="Unable to delete flavor {name}".format( error_message="Unable to delete flavor {name}".format(
name=name_or_id)) name=name_or_id))
@ -10549,7 +10479,7 @@ class OpenStackCloud(_normalize.Normalizer):
:raises: OpenStackCloudResourceNotFound if flavor ID is not found. :raises: OpenStackCloudResourceNotFound if flavor ID is not found.
""" """
_adapter._json_response( _adapter._json_response(
self._conn.compute.post( self.compute.post(
"/flavors/{id}/os-extra_specs".format(id=flavor_id), "/flavors/{id}/os-extra_specs".format(id=flavor_id),
json=dict(extra_specs=extra_specs)), json=dict(extra_specs=extra_specs)),
error_message="Unable to set flavor specs") error_message="Unable to set flavor specs")
@ -10565,7 +10495,7 @@ class OpenStackCloud(_normalize.Normalizer):
""" """
for key in keys: for key in keys:
_adapter._json_response( _adapter._json_response(
self._conn.compute.delete( self.compute.delete(
"/flavors/{id}/os-extra_specs/{key}".format( "/flavors/{id}/os-extra_specs/{key}".format(
id=flavor_id, key=key)), id=flavor_id, key=key)),
error_message="Unable to delete flavor spec {0}".format(key)) error_message="Unable to delete flavor spec {0}".format(key))
@ -10581,7 +10511,7 @@ class OpenStackCloud(_normalize.Normalizer):
access_key = '{action}TenantAccess'.format(action=action) access_key = '{action}TenantAccess'.format(action=action)
_adapter._json_response( _adapter._json_response(
self._conn.compute.post(endpoint, json={access_key: access})) self.compute.post(endpoint, json={access_key: access}))
def add_flavor_access(self, flavor_id, project_id): def add_flavor_access(self, flavor_id, project_id):
"""Grant access to a private flavor for a project/tenant. """Grant access to a private flavor for a project/tenant.
@ -10613,7 +10543,7 @@ class OpenStackCloud(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error. :raises: OpenStackCloudException on operation error.
""" """
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get( self.compute.get(
'/flavors/{id}/os-flavor-access'.format(id=flavor_id)), '/flavors/{id}/os-flavor-access'.format(id=flavor_id)),
error_message=( error_message=(
"Error trying to list access from flavorID {flavor}".format( "Error trying to list access from flavorID {flavor}".format(
@ -10892,7 +10822,7 @@ class OpenStackCloud(_normalize.Normalizer):
""" """
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('/os-hypervisors/detail'), self.compute.get('/os-hypervisors/detail'),
error_message="Error fetching hypervisor list") error_message="Error fetching hypervisor list")
return self._get_and_munchify('hypervisors', data) return self._get_and_munchify('hypervisors', data)
@ -10917,7 +10847,7 @@ class OpenStackCloud(_normalize.Normalizer):
""" """
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get('/os-aggregates'), self.compute.get('/os-aggregates'),
error_message="Error fetching aggregate list") error_message="Error fetching aggregate list")
return self._get_and_munchify('aggregates', data) return self._get_and_munchify('aggregates', data)
@ -10953,7 +10883,7 @@ class OpenStackCloud(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error. :raises: OpenStackCloudException on operation error.
""" """
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/os-aggregates', '/os-aggregates',
json={'aggregate': { json={'aggregate': {
'name': name, 'name': name,
@ -10981,7 +10911,7 @@ class OpenStackCloud(_normalize.Normalizer):
"Host aggregate %s not found." % name_or_id) "Host aggregate %s not found." % name_or_id)
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.put( self.compute.put(
'/os-aggregates/{id}'.format(id=aggregate['id']), '/os-aggregates/{id}'.format(id=aggregate['id']),
json={'aggregate': kwargs}), json={'aggregate': kwargs}),
error_message="Error updating aggregate {name}".format( error_message="Error updating aggregate {name}".format(
@ -11003,7 +10933,7 @@ class OpenStackCloud(_normalize.Normalizer):
return False return False
return _adapter._json_response( return _adapter._json_response(
self._conn.compute.delete( self.compute.delete(
'/os-aggregates/{id}'.format(id=aggregate['id'])), '/os-aggregates/{id}'.format(id=aggregate['id'])),
error_message="Error deleting aggregate {name}".format( error_message="Error deleting aggregate {name}".format(
name=name_or_id)) name=name_or_id))
@ -11030,7 +10960,7 @@ class OpenStackCloud(_normalize.Normalizer):
name=name_or_id) name=name_or_id)
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/os-aggregates/{id}/action'.format(id=aggregate['id']), '/os-aggregates/{id}/action'.format(id=aggregate['id']),
json={'set_metadata': {'metadata': metadata}}), json={'set_metadata': {'metadata': metadata}}),
error_message=err_msg) error_message=err_msg)
@ -11053,7 +10983,7 @@ class OpenStackCloud(_normalize.Normalizer):
host=host_name, name=name_or_id) host=host_name, name=name_or_id)
return _adapter._json_response( return _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/os-aggregates/{id}/action'.format(id=aggregate['id']), '/os-aggregates/{id}/action'.format(id=aggregate['id']),
json={'add_host': {'host': host_name}}), json={'add_host': {'host': host_name}}),
error_message=err_msg) error_message=err_msg)
@ -11075,7 +11005,7 @@ class OpenStackCloud(_normalize.Normalizer):
host=host_name, name=name_or_id) host=host_name, name=name_or_id)
return _adapter._json_response( return _adapter._json_response(
self._conn.compute.post( self.compute.post(
'/os-aggregates/{id}/action'.format(id=aggregate['id']), '/os-aggregates/{id}/action'.format(id=aggregate['id']),
json={'remove_host': {'host': host_name}}), json={'remove_host': {'host': host_name}}),
error_message=err_msg) error_message=err_msg)
@ -11167,7 +11097,7 @@ class OpenStackCloud(_normalize.Normalizer):
kwargs['force'] = True kwargs['force'] = True
_adapter._json_response( _adapter._json_response(
self._conn.compute.put( self.compute.put(
'/os-quota-sets/{project}'.format(project=proj.id), '/os-quota-sets/{project}'.format(project=proj.id),
json={'quota_set': kwargs}), json={'quota_set': kwargs}),
error_message="No valid quota or resource") error_message="No valid quota or resource")
@ -11184,7 +11114,7 @@ class OpenStackCloud(_normalize.Normalizer):
if not proj: if not proj:
raise OpenStackCloudException("project does not exist") raise OpenStackCloudException("project does not exist")
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get( self.compute.get(
'/os-quota-sets/{project}'.format(project=proj.id))) '/os-quota-sets/{project}'.format(project=proj.id)))
return self._get_and_munchify('quota_set', data) return self._get_and_munchify('quota_set', data)
@ -11201,7 +11131,7 @@ class OpenStackCloud(_normalize.Normalizer):
if not proj: if not proj:
raise OpenStackCloudException("project does not exist") raise OpenStackCloudException("project does not exist")
return _adapter._json_response( return _adapter._json_response(
self._conn.compute.delete( self.compute.delete(
'/os-quota-sets/{project}'.format(project=proj.id))) '/os-quota-sets/{project}'.format(project=proj.id)))
def get_compute_usage(self, name_or_id, start=None, end=None): def get_compute_usage(self, name_or_id, start=None, end=None):
@ -11260,7 +11190,7 @@ class OpenStackCloud(_normalize.Normalizer):
name=proj.id)) name=proj.id))
data = _adapter._json_response( data = _adapter._json_response(
self._conn.compute.get( self.compute.get(
'/os-simple-tenant-usage/{project}'.format(project=proj.id), '/os-simple-tenant-usage/{project}'.format(project=proj.id),
params=dict(start=start.isoformat(), end=end.isoformat())), params=dict(start=start.isoformat(), end=end.isoformat())),
error_message="Unable to get usage for project: {name}".format( error_message="Unable to get usage for project: {name}".format(

@ -211,7 +211,8 @@ def from_config(cloud=None, config=None, options=None, **kwargs):
return Connection(config=config) return Connection(config=config)
class Connection(six.with_metaclass(_meta.ConnectionMeta)): class Connection(six.with_metaclass(_meta.ConnectionMeta,
_cloud.OpenStackCloud)):
def __init__(self, cloud=None, config=None, session=None, def __init__(self, cloud=None, config=None, session=None,
app_name=None, app_version=None, app_name=None, app_version=None,
@ -219,6 +220,8 @@ class Connection(six.with_metaclass(_meta.ConnectionMeta)):
# python-openstackclient to not use the profile interface. # python-openstackclient to not use the profile interface.
authenticator=None, profile=None, authenticator=None, profile=None,
extra_services=None, extra_services=None,
strict=False,
use_direct_get=False,
**kwargs): **kwargs):
"""Create a connection to a cloud. """Create a connection to a cloud.
@ -305,17 +308,23 @@ class Connection(six.with_metaclass(_meta.ConnectionMeta)):
# TODO(mordred) Expose constructor option for this in OCC # TODO(mordred) Expose constructor option for this in OCC
self.config._keystone_session = session self.config._keystone_session = session
self.session = self.config.get_session() self._session = None
# Hide a reference to the connection on the session to help with
# backwards compatibility for folks trying to just pass conn.session
# to a Resource method's session argument.
self.session._sdk_connection = self
self._proxies = {} self._proxies = {}
self.cloud = _cloud.OpenStackCloud( self.use_direct_get = use_direct_get
cloud_config=self.config, self.strict_mode = strict
manager=self.task_manager, # Call the OpenStackCloud constructor while we work on integrating
conn=self) # things better.
_cloud.OpenStackCloud.__init__(self)
@property
def session(self):
if not self._session:
self._session = self.config.get_session()
# Hide a reference to the connection on the session to help with
# backwards compatibility for folks trying to just pass
# conn.session to a Resource method's session argument.
self.session._sdk_connection = self
return self._session
def add_service(self, service): def add_service(self, service):
"""Add a service to the Connection. """Add a service to the Connection.

@ -16,7 +16,7 @@ import os
import openstack.config as occ import openstack.config as occ
import openstack.cloud from openstack import connection
from openstack.tests import base from openstack.tests import base
@ -33,19 +33,17 @@ class BaseFunctionalTestCase(base.TestCase):
self._set_operator_cloud() self._set_operator_cloud()
self.identity_version = \ self.identity_version = \
self.operator_cloud.cloud_config.get_api_version('identity') self.operator_cloud.config.get_api_version('identity')
def _set_user_cloud(self, **kwargs): def _set_user_cloud(self, **kwargs):
user_config = self.config.get_one( user_config = self.config.get_one(
cloud=self._demo_name, **kwargs) cloud=self._demo_name, **kwargs)
self.user_cloud = openstack.cloud.OpenStackCloud( self.user_cloud = connection.Connection(config=user_config)
cloud_config=user_config)
def _set_operator_cloud(self, **kwargs): def _set_operator_cloud(self, **kwargs):
operator_config = self.config.get_one( operator_config = self.config.get_one(
cloud=self._op_name, **kwargs) cloud=self._op_name, **kwargs)
self.operator_cloud = openstack.cloud.OpenStackCloud( self.operator_cloud = connection.Connection(config=operator_config)
cloud_config=operator_config)
def pick_image(self): def pick_image(self):
images = self.user_cloud.list_images() images = self.user_cloud.list_images()

@ -27,7 +27,7 @@ class TestDomain(base.BaseFunctionalTestCase):
def setUp(self): def setUp(self):
super(TestDomain, self).setUp() super(TestDomain, self).setUp()
i_ver = self.operator_cloud.cloud_config.get_api_version('identity') i_ver = self.operator_cloud.config.get_api_version('identity')
if i_ver in ('2', '2.0'): if i_ver in ('2', '2.0'):
self.skipTest('Identity service does not support domains') self.skipTest('Identity service does not support domains')
self.domain_prefix = self.getUniqueString('domain') self.domain_prefix = self.getUniqueString('domain')

@ -103,7 +103,7 @@ class TestEndpoints(base.KeystoneBaseFunctionalTestCase):
self.assertIsNotNone(endpoints[0].get('id')) self.assertIsNotNone(endpoints[0].get('id'))
def test_update_endpoint(self): def test_update_endpoint(self):
ver = self.operator_cloud.cloud_config.get_api_version('identity') ver = self.operator_cloud.config.get_api_version('identity')
if ver.startswith('2'): if ver.startswith('2'):
# NOTE(SamYaple): Update endpoint only works with v3 api # NOTE(SamYaple): Update endpoint only works with v3 api
self.assertRaises(OpenStackCloudUnavailableFeature, self.assertRaises(OpenStackCloudUnavailableFeature,

@ -27,7 +27,7 @@ class TestGroup(base.BaseFunctionalTestCase):
def setUp(self): def setUp(self):
super(TestGroup, self).setUp() super(TestGroup, self).setUp()
i_ver = self.operator_cloud.cloud_config.get_api_version('identity') i_ver = self.operator_cloud.config.get_api_version('identity')
if i_ver in ('2', '2.0'): if i_ver in ('2', '2.0'):
self.skipTest('Identity service does not support groups') self.skipTest('Identity service does not support groups')
self.group_prefix = self.getUniqueString('group') self.group_prefix = self.getUniqueString('group')

@ -73,7 +73,7 @@ class TestProject(base.KeystoneBaseFunctionalTestCase):
new_cloud = self.operator_cloud.connect_as_project(project) new_cloud = self.operator_cloud.connect_as_project(project)
self.add_info_on_exception( self.add_info_on_exception(
'new_cloud_config', pprint.pformat(new_cloud.cloud_config.config)) 'new_cloud_config', pprint.pformat(new_cloud.config.config))
location = new_cloud.current_location location = new_cloud.current_location
self.assertEqual(project_name, location['project']['name']) self.assertEqual(project_name, location['project']['name'])

@ -65,7 +65,7 @@ class TestServices(base.KeystoneBaseFunctionalTestCase):
self.assertIsNotNone(service.get('id')) self.assertIsNotNone(service.get('id'))
def test_update_service(self): def test_update_service(self):
ver = self.operator_cloud.cloud_config.get_api_version('identity') ver = self.operator_cloud.config.get_api_version('identity')
if ver.startswith('2'): if ver.startswith('2'):
# NOTE(SamYaple): Update service only works with v3 api # NOTE(SamYaple): Update service only works with v3 api
self.assertRaises(OpenStackCloudUnavailableFeature, self.assertRaises(OpenStackCloudUnavailableFeature,

@ -42,7 +42,7 @@ class TestUsers(base.KeystoneBaseFunctionalTestCase):
def _create_user(self, **kwargs): def _create_user(self, **kwargs):
domain_id = None domain_id = None
i_ver = self.operator_cloud.cloud_config.get_api_version('identity') i_ver = self.operator_cloud.config.get_api_version('identity')
if i_ver not in ('2', '2.0'): if i_ver not in ('2', '2.0'):
domain = self.operator_cloud.get_domain('default') domain = self.operator_cloud.get_domain('default')
domain_id = domain['id'] domain_id = domain['id']
@ -143,7 +143,7 @@ class TestUsers(base.KeystoneBaseFunctionalTestCase):
self.assertIsNotNone(new_cloud.service_catalog) self.assertIsNotNone(new_cloud.service_catalog)
def test_users_and_groups(self): def test_users_and_groups(self):
i_ver = self.operator_cloud.cloud_config.get_api_version('identity') i_ver = self.operator_cloud.config.get_api_version('identity')
if i_ver in ('2', '2.0'): if i_ver in ('2', '2.0'):
self.skipTest('Identity service does not support groups') self.skipTest('Identity service does not support groups')

@ -119,10 +119,11 @@ class BaseTestCase(base.TestCase):
secure_files=['non-existant']) secure_files=['non-existant'])
self.cloud_config = self.config.get_one( self.cloud_config = self.config.get_one(
cloud=test_cloud, validate=False) cloud=test_cloud, validate=False)
self.cloud = openstack.cloud.OpenStackCloud( self.cloud = openstack.connection.Connection(
cloud_config=self.cloud_config) config=self.cloud_config,
self.strict_cloud = openstack.cloud.OpenStackCloud( strict=False)
cloud_config=self.cloud_config, self.strict_cloud = openstack.connection.Connection(
config=self.cloud_config,
strict=True) strict=True)
@ -460,8 +461,7 @@ class RequestsMockTestCase(BaseTestCase):
cloud=test_cloud, validate=True, **kwargs) cloud=test_cloud, validate=True, **kwargs)
self.conn = openstack.connection.Connection( self.conn = openstack.connection.Connection(
config=self.cloud_config) config=self.cloud_config)
self.cloud = openstack.cloud.OpenStackCloud( self.cloud = self.conn
cloud_config=self.cloud_config)
def get_glance_discovery_mock_dict( def get_glance_discovery_mock_dict(
self, self,

@ -58,7 +58,7 @@ class TestImage(BaseTestImage):
self.use_glance() self.use_glance()
def test_config_v1(self): def test_config_v1(self):
self.cloud.cloud_config.config['image_api_version'] = '1' self.cloud.config.config['image_api_version'] = '1'
# We override the scheme of the endpoint with the scheme of the service # We override the scheme of the endpoint with the scheme of the service
# because glance has a bug where it doesn't return https properly. # because glance has a bug where it doesn't return https properly.
self.assertEqual( self.assertEqual(
@ -68,7 +68,7 @@ class TestImage(BaseTestImage):
'1', self.cloud_config.get_api_version('image')) '1', self.cloud_config.get_api_version('image'))
def test_config_v2(self): def test_config_v2(self):
self.cloud.cloud_config.config['image_api_version'] = '2' self.cloud.config.config['image_api_version'] = '2'
# We override the scheme of the endpoint with the scheme of the service # We override the scheme of the endpoint with the scheme of the service
# because glance has a bug where it doesn't return https properly. # because glance has a bug where it doesn't return https properly.
self.assertEqual( self.assertEqual(
@ -937,7 +937,7 @@ class TestImageV1Only(base.RequestsMockTestCase):
def test_config_v1(self): def test_config_v1(self):
self.cloud.cloud_config.config['image_api_version'] = '1' self.cloud.config.config['image_api_version'] = '1'
# We override the scheme of the endpoint with the scheme of the service # We override the scheme of the endpoint with the scheme of the service
# because glance has a bug where it doesn't return https properly. # because glance has a bug where it doesn't return https properly.
self.assertEqual( self.assertEqual(
@ -946,7 +946,7 @@ class TestImageV1Only(base.RequestsMockTestCase):
self.assertTrue(self.cloud._is_client_version('image', 1)) self.assertTrue(self.cloud._is_client_version('image', 1))
def test_config_v2(self): def test_config_v2(self):
self.cloud.cloud_config.config['image_api_version'] = '2' self.cloud.config.config['image_api_version'] = '2'
# We override the scheme of the endpoint with the scheme of the service # We override the scheme of the endpoint with the scheme of the service
# because glance has a bug where it doesn't return https properly. # because glance has a bug where it doesn't return https properly.
self.assertEqual( self.assertEqual(
@ -962,7 +962,7 @@ class TestImageV2Only(base.RequestsMockTestCase):
self.use_glance(image_version_json='image-version-v2.json') self.use_glance(image_version_json='image-version-v2.json')
def test_config_v1(self): def test_config_v1(self):
self.cloud.cloud_config.config['image_api_version'] = '1' self.cloud.config.config['image_api_version'] = '1'
# We override the scheme of the endpoint with the scheme of the service # We override the scheme of the endpoint with the scheme of the service
# because glance has a bug where it doesn't return https properly. # because glance has a bug where it doesn't return https properly.
self.assertEqual( self.assertEqual(
@ -971,7 +971,7 @@ class TestImageV2Only(base.RequestsMockTestCase):
self.assertTrue(self.cloud._is_client_version('image', 2)) self.assertTrue(self.cloud._is_client_version('image', 2))
def test_config_v2(self): def test_config_v2(self):
self.cloud.cloud_config.config['image_api_version'] = '2' self.cloud.config.config['image_api_version'] = '2'
# We override the scheme of the endpoint with the scheme of the service # We override the scheme of the endpoint with the scheme of the service
# because glance has a bug where it doesn't return https properly. # because glance has a bug where it doesn't return https properly.
self.assertEqual( self.assertEqual(

@ -12,10 +12,8 @@
import mock import mock
from openstack.cloud import exc
from openstack.cloud import inventory from openstack.cloud import inventory
import openstack.config import openstack.config
from openstack.config import exceptions as occ_exc
from openstack.tests import fakes from openstack.tests import fakes
from openstack.tests.unit import base from openstack.tests.unit import base
@ -26,7 +24,7 @@ class TestInventory(base.TestCase):
super(TestInventory, self).setUp() super(TestInventory, self).setUp()
@mock.patch("openstack.config.loader.OpenStackConfig") @mock.patch("openstack.config.loader.OpenStackConfig")
@mock.patch("openstack.cloud.OpenStackCloud") @mock.patch("openstack.connection.Connection")
def test__init(self, mock_cloud, mock_config): def test__init(self, mock_cloud, mock_config):
mock_config.return_value.get_all.return_value = [{}] mock_config.return_value.get_all.return_value = [{}]
@ -40,7 +38,7 @@ class TestInventory(base.TestCase):
self.assertTrue(mock_config.return_value.get_all.called) self.assertTrue(mock_config.return_value.get_all.called)
@mock.patch("openstack.config.loader.OpenStackConfig") @mock.patch("openstack.config.loader.OpenStackConfig")
@mock.patch("openstack.cloud.OpenStackCloud") @mock.patch("openstack.connection.Connection")
def test__init_one_cloud(self, mock_cloud, mock_config): def test__init_one_cloud(self, mock_cloud, mock_config):
mock_config.return_value.get_one.return_value = [{}] mock_config.return_value.get_one.return_value = [{}]
@ -56,23 +54,7 @@ class TestInventory(base.TestCase):
'supercloud') 'supercloud')
@mock.patch("openstack.config.loader.OpenStackConfig") @mock.patch("openstack.config.loader.OpenStackConfig")
@mock.patch("openstack.cloud.OpenStackCloud") @mock.patch("openstack.connection.Connection")
def test__raise_exception_on_no_cloud(self, mock_cloud, mock_config):
"""
Test that when os-client-config can't find a named cloud, a
shade exception is emitted.
"""
mock_config.return_value.get_one.side_effect = (
occ_exc.OpenStackConfigException()
)
self.assertRaises(exc.OpenStackCloudException,
inventory.OpenStackInventory,
cloud='supercloud')
mock_config.return_value.get_one.assert_called_once_with(
'supercloud')
@mock.patch("openstack.config.loader.OpenStackConfig")
@mock.patch("openstack.cloud.OpenStackCloud")
def test_list_hosts(self, mock_cloud, mock_config): def test_list_hosts(self, mock_cloud, mock_config):
mock_config.return_value.get_all.return_value = [{}] mock_config.return_value.get_all.return_value = [{}]
@ -91,7 +73,7 @@ class TestInventory(base.TestCase):
self.assertEqual([server], ret) self.assertEqual([server], ret)
@mock.patch("openstack.config.loader.OpenStackConfig") @mock.patch("openstack.config.loader.OpenStackConfig")
@mock.patch("openstack.cloud.OpenStackCloud") @mock.patch("openstack.connection.Connection")
def test_list_hosts_no_detail(self, mock_cloud, mock_config): def test_list_hosts_no_detail(self, mock_cloud, mock_config):
mock_config.return_value.get_all.return_value = [{}] mock_config.return_value.get_all.return_value = [{}]
@ -110,7 +92,7 @@ class TestInventory(base.TestCase):
self.assertFalse(inv.clouds[0].get_openstack_vars.called) self.assertFalse(inv.clouds[0].get_openstack_vars.called)
@mock.patch("openstack.config.loader.OpenStackConfig") @mock.patch("openstack.config.loader.OpenStackConfig")
@mock.patch("openstack.cloud.OpenStackCloud") @mock.patch("openstack.connection.Connection")
def test_search_hosts(self, mock_cloud, mock_config): def test_search_hosts(self, mock_cloud, mock_config):
mock_config.return_value.get_all.return_value = [{}] mock_config.return_value.get_all.return_value = [{}]
@ -126,7 +108,7 @@ class TestInventory(base.TestCase):
self.assertEqual([server], ret) self.assertEqual([server], ret)
@mock.patch("openstack.config.loader.OpenStackConfig") @mock.patch("openstack.config.loader.OpenStackConfig")
@mock.patch("openstack.cloud.OpenStackCloud") @mock.patch("openstack.connection.Connection")
def test_get_host(self, mock_cloud, mock_config): def test_get_host(self, mock_cloud, mock_config):
mock_config.return_value.get_all.return_value = [{}] mock_config.return_value.get_all.return_value = [{}]

@ -1,4 +1,4 @@
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. # Copyrigh
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -24,8 +24,12 @@ PUBLIC_V4 = '192.0.2.99'
PUBLIC_V6 = '2001:0db8:face:0da0:face::0b00:1c' # rfc3849 PUBLIC_V6 = '2001:0db8:face:0da0:face::0b00:1c' # rfc3849
class FakeCloud(object): class FakeConfig(object):
region_name = 'test-region' region_name = 'test-region'
class FakeCloud(object):
config = FakeConfig()
name = 'test-name' name = 'test-name'
private = False private = False
force_ipv4 = False force_ipv4 = False
@ -586,7 +590,7 @@ class TestMeta(base.RequestsMockTestCase):
def test_get_server_cloud_rackspace_v6( def test_get_server_cloud_rackspace_v6(
self, mock_get_flavor_name, mock_get_image_name, self, mock_get_flavor_name, mock_get_image_name,
mock_get_volumes): mock_get_volumes):
self.cloud.cloud_config.config['has_network'] = False self.cloud.config.config['has_network'] = False
self.cloud._floating_ip_source = None self.cloud._floating_ip_source = None
self.cloud.force_ipv4 = False self.cloud.force_ipv4 = False
self.cloud._local_ipv6 = True self.cloud._local_ipv6 = True
@ -830,7 +834,7 @@ class TestMeta(base.RequestsMockTestCase):
def test_get_server_external_ipv4_nova_public(self): def test_get_server_external_ipv4_nova_public(self):
# Testing Clouds w/o Neutron and a network named public # Testing Clouds w/o Neutron and a network named public
self.cloud.cloud_config.config['has_network'] = False self.cloud.config.config['has_network'] = False
srv = fakes.make_fake_server( srv = fakes.make_fake_server(
server_id='test-id', name='test-name', status='ACTIVE', server_id='test-id', name='test-name', status='ACTIVE',
@ -841,7 +845,7 @@ class TestMeta(base.RequestsMockTestCase):
def test_get_server_external_ipv4_nova_none(self): def test_get_server_external_ipv4_nova_none(self):
# Testing Clouds w/o Neutron or a globally routable IP # Testing Clouds w/o Neutron or a globally routable IP
self.cloud.cloud_config.config['has_network'] = False self.cloud.config.config['has_network'] = False
srv = fakes.make_fake_server( srv = fakes.make_fake_server(
server_id='test-id', name='test-name', status='ACTIVE', server_id='test-id', name='test-name', status='ACTIVE',

@ -46,7 +46,7 @@ class TestOperatorCloud(base.RequestsMockTestCase):
session_mock.get_endpoint.side_effect = side_effect session_mock.get_endpoint.side_effect = side_effect
get_session_mock.return_value = session_mock get_session_mock.return_value = session_mock
self.cloud.name = 'testcloud' self.cloud.name = 'testcloud'
self.cloud.region_name = 'testregion' self.cloud.config.region_name = 'testregion'
with testtools.ExpectedException( with testtools.ExpectedException(
exc.OpenStackCloudException, exc.OpenStackCloudException,
"Error getting image endpoint on testcloud:testregion:" "Error getting image endpoint on testcloud:testregion:"

@ -30,7 +30,7 @@ class TestFromSession(base.RequestsMockTestCase):
def test_from_session(self): def test_from_session(self):
config = cloud_region.from_session( config = cloud_region.from_session(
self.cloud.keystone_session, region_name=self.test_region) self.cloud.session, region_name=self.test_region)
self.assertEqual(config.name, 'identity.example.com') self.assertEqual(config.name, 'identity.example.com')
if not self.test_region: if not self.test_region:
self.assertIsNone(config.region_name) self.assertIsNone(config.region_name)

@ -0,0 +1,5 @@
---
features:
- |
All of the methods formerly part of the ``shade`` library have been added
to the `openstack.connection.Connection`` object.