def get_template_contents(template_file=None, template_url=None, template_object=None, object_request=None, files=None, existing=False): is_object = False tpl = None # Transform a bare file path to a file:// URL. if template_file: template_url = utils.normalise_file_path_to_url(template_file) if template_url: tpl = request.urlopen(template_url).read() elif template_object: is_object = True template_url = template_object tpl = object_request and object_request('GET', template_object) elif existing: return {}, None else: raise exc.OpenStackCloudException('Must provide one of template_file,' ' template_url or template_object') if not tpl: raise exc.OpenStackCloudException('Could not fetch template from %s' % template_url) try: if isinstance(tpl, six.binary_type): tpl = tpl.decode('utf-8') template = template_format.parse(tpl) except ValueError as e: raise exc.OpenStackCloudException( 'Error parsing template %(url)s %(error)s' % { 'url': template_url, 'error': e }) tmpl_base_url = utils.base_url_for_url(template_url) if files is None: files = {} resolve_template_get_files(template, files, tmpl_base_url, is_object, object_request) return files, template
def test_create_floating_ip_exception(self, mock_logger): self.mock_shade_client.create_floating_ip.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.create_floating_ip( self.mock_shade_client, self.network_name_or_id) mock_logger.error.assert_called_once() self.assertIsNone(output)
def test_delete_volume_exception(self, mock_logger): self.mock_shade_client.delete_volume.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.delete_volume(self.mock_shade_client, 'volume_name_or_id') mock_logger.error.assert_called_once() self.assertFalse(output)
def neutron_exceptions(error_message): try: yield except neutron_exc.NotFound as e: raise exc.OpenStackCloudResourceNotFound("{msg}: {exc}".format( msg=error_message, exc=str(e))) except neutron_exc.NeutronClientException as e: if e.status_code == 404: raise exc.OpenStackCloudURINotFound("{msg}: {exc}".format( msg=error_message, exc=str(e))) else: raise exc.OpenStackCloudException("{msg}: {exc}".format( msg=error_message, exc=str(e))) except Exception as e: raise exc.OpenStackCloudException("{msg}: {exc}".format( msg=error_message, exc=str(e)))
def _iterate_timeout(timeout, message, wait=2): """Iterate and raise an exception on timeout. This is a generator that will continually yield and sleep for wait seconds, and if the timeout is reached, will raise an exception with <message>. """ log = _log.setup_logging('shade.iterate_timeout') try: # None as a wait winds up flowing well in the per-resource cache # flow. We could spread this logic around to all of the calling # points, but just having this treat None as "I don't have a value" # seems friendlier if wait is None: wait = 2 elif wait == 0: # wait should be < timeout, unless timeout is None wait = 0.1 if timeout is None else min(0.1, timeout) wait = float(wait) except ValueError: raise exc.OpenStackCloudException( "Wait value must be an int or float value. {wait} given" " instead".format(wait=wait)) start = time.time() count = 0 while (timeout is None) or (time.time() < start + timeout): count += 1 yield count log.debug('Waiting %s seconds', wait) time.sleep(wait) raise exc.OpenStackCloudTimeout(message)
def test_delete_neutron_net_exception(self, mock_logger): self.mock_shade_client.delete_network.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.delete_neutron_net(self.mock_shade_client, 'network_id') self.assertFalse(output) mock_logger.error.assert_called_once()
def _get_entity(func, name_or_id, filters, **kwargs): """Return a single entity from the list returned by a given method. :param callable func: A function that takes `name_or_id` and `filters` as parameters and returns a list of entities to filter. :param string name_or_id: The name or ID of the entity being filtered or a dict :param filters: A dictionary of meta data to use for further filtering. OR A string containing a jmespath expression for further filtering. Example:: "[?last_name==`Smith`] | [?other.gender]==`Female`]" """ # Sometimes in the control flow of shade, we already have an object # fetched. Rather than then needing to pull the name or id out of that # object, pass it in here and rely on caching to prevent us from making # an additional call, it's simple enough to test to see if we got an # object and just short-circuit return it. if hasattr(name_or_id, 'id'): return name_or_id entities = func(name_or_id, filters, **kwargs) if not entities: return None if len(entities) > 1: raise exc.OpenStackCloudException("Multiple matches found for %s" % name_or_id) return entities[0]
def test_remove_router_interface_exception(self, mock_logger): self.mock_shade_client.remove_router_interface.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.remove_router_interface( self.mock_shade_client, self.router) mock_logger.error.assert_called_once() self.assertFalse(output)
def openstack_clouds(config=None, debug=False, cloud=None, strict=False, app_name=None, app_version=None, use_direct_get=False): if not config: config = _get_openstack_config(app_name, app_version) try: if cloud is None: return [ OpenStackCloud(cloud=f.name, debug=debug, cloud_config=f, strict=strict, use_direct_get=use_direct_get, **f.config) for f in config.get_all_clouds() ] else: return [ OpenStackCloud(cloud=f.name, debug=debug, cloud_config=f, strict=strict, use_direct_get=use_direct_get, **f.config) for f in config.get_all_clouds() if f.name == cloud ] except keystoneauth1.exceptions.auth_plugins.NoMatchingPlugin as e: raise exc.OpenStackCloudException( "Invalid cloud configuration: {exc}".format(exc=str(e)))
def safe_dict_max(key, data): """Safely find the maximum for a given key in a list of dict objects. This will find the maximum integer value for specific dictionary key across a list of dictionaries. The values for the given key MUST be integers, or string representations of an integer. The dictionary key does not have to be present in all (or any) of the elements/dicts within the data set. :param string key: The dictionary key to search for the maximum value. :param list data: List of dicts to use for the data set. :returns: None if the field was not not found in any elements, or the maximum value for the field otherwise. """ max_value = None for d in data: if (key in d) and (d[key] is not None): try: val = int(d[key]) except ValueError: raise exc.OpenStackCloudException( "Search for maximum value failed. " "Value for {key} is not an integer: {value}".format( key=key, value=d[key])) if (max_value is None) or (val > max_value): max_value = val return max_value
def shade_exceptions(error_message=None): """Context manager for dealing with shade exceptions. :param string error_message: String to use for the exception message content on non-OpenStackCloudExceptions. Useful for avoiding wrapping shade OpenStackCloudException exceptions within themselves. Code called from within the context may throw such exceptions without having to catch and reraise them. Non-OpenStackCloudException exceptions thrown within the context will be wrapped and the exception message will be appended to the given error message. """ try: yield except exc.OpenStackCloudException: raise except nova_exc.BadRequest as e: if error_message is None: error_message = str(e) raise exc.OpenStackCloudBadRequest(error_message) except Exception as e: if error_message is None: error_message = str(e) raise exc.OpenStackCloudException(error_message)
def test_create_volume_fail(self, mock_logger): self.mock_shade_client.create_volume.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.create_volume(self.mock_shade_client, self.size) mock_logger.error.assert_called_once() self.assertIsNone(output)
def test_list_images_exception(self, mock_logger): mock_shade_client = mock.MagicMock() mock_shade_client.list_images = mock.MagicMock() mock_shade_client.list_images.side_effect = ( exc.OpenStackCloudException('error message')) images = openstack_utils.list_images(mock_shade_client) mock_logger.error.assert_called_once() self.assertFalse(images)
def test_create_security_group_rule_exception(self): self.mock_shade_client.create_security_group_rule.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.create_security_group_rule( self.mock_shade_client, self.secgroup_name_or_id) self.mock_log.error.assert_called_once() self.assertFalse(output)
def test_create_security_group_full_non_existing_security_group(self): self.mock_shade_client.get_security_group.return_value = None self.mock_shade_client.create_security_group.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.create_security_group_full( self.mock_shade_client, self.sg_name, self.sg_description) self.mock_log.error.assert_called_once() self.assertIsNone(output)
def test_create_neutron_subnet_exception(self, mock_logger): self.mock_shade_client.create_router.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.create_neutron_router( self.mock_shade_client) mock_logger.error.assert_called_once() self.assertIsNone(output)
def test_get_flavor_exception(self, mock_logger): self.mock_shade_client = mock.Mock() self.mock_shade_client.get_flavor.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.get_flavor(self.mock_shade_client, 'flavor_name_or_id') mock_logger.error.assert_called_once() self.assertIsNone(output)
def test_attach_volume_to_server_fail(self, mock_logger): self.mock_shade_client = mock.Mock() self.mock_shade_client.attach_volume.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.attach_volume_to_server( self.mock_shade_client, 'server_name_or_id', 'volume_name_or_id') mock_logger.error.assert_called_once() self.assertFalse(output)
def test_create_instance_and_wait_for_active_fail(self, mock_logger): self.mock_shade_client = mock.Mock() self.mock_shade_client.create_server.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.create_instance_and_wait_for_active( self.mock_shade_client, 'server_name', 'image_name', 'flavor_name') mock_logger.error.assert_called_once() self.assertIsNone(output)
def heat_exceptions(error_message): try: yield except heat_exc.NotFound as e: raise exc.OpenStackCloudResourceNotFound("{msg}: {exc}".format( msg=error_message, exc=str(e))) except Exception as e: raise exc.OpenStackCloudException("{msg}: {exc}".format( msg=error_message, exc=str(e)))
def _get_aggregate(cloud, name): aggs = cloud.nova_client.aggregates.list() entities = [x for x in aggs if x.id == name or x.name == name] if not entities: return None if len(entities) > 1: raise exc.OpenStackCloudException("Multiple matches found for %s" % name) return entities[0]
def test_create_image_exception(self): self.mock_shade_client.get_image_id.return_value = None self.mock_shade_client.create_image.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.create_image(self.mock_shade_client, self.name) self.mock_log.error.assert_called_once() self.assertIsNone(output)
def test_register_machine_port_create_failed(self, mock_client): nics = [{'mac': '00:00:00:00:00:00'}] mock_client.port.create.side_effect = ( exc.OpenStackCloudException("Error")) self.assertRaises(exc.OpenStackCloudException, self.cloud.register_machine, nics) self.assertTrue(mock_client.node.create.called) self.assertTrue(mock_client.port.create.called) self.assertTrue(mock_client.node.delete.called)
def test_detach_volume_exception(self, mock_logger, mock_get_server): self.mock_shade_client = mock.Mock() mock_get_server.return_value = {'server_dict'} self.mock_shade_client.get_volume.return_value = {'volume_dict'} self.mock_shade_client.detach_volume.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.detach_volume(self.mock_shade_client, 'server_name_or_id', 'volume_name_or_id') mock_logger.error.assert_called_once() self.assertFalse(output)
def ironic_client(self): # Trigger discovery from ksa. This will make ironicclient and # keystoneauth1.adapter.Adapter code paths both go through discovery. # ironicclient does its own magic with discovery, so we won't # pass an endpoint_override here like we do for keystoneclient. # Just so it's not wasted though, make sure we can handle the # min microversion we need. needed = self._get_legacy_ironic_microversion() # TODO(mordred) Bug in ksa - don't do microversion matching for # auth_type = admin_token. Remove this if when the fix lands. if (hasattr(plugin.BaseAuthPlugin, 'get_endpoint_data') or self.cloud_config.config['auth_type'] not in ('admin_token', 'none')): # TODO(mordred) once we're on REST properly, we need a better # method for matching requested and available microversion endpoint_data = self._baremetal_client.get_endpoint_data() if not endpoint_data.min_microversion: raise exc.OpenStackCloudException( "shade needs an ironic that supports microversions") if endpoint_data.min_microversion[1] > int(needed[-1]): raise exc.OpenStackCloudException( "shade needs an ironic that supports microversion {needed}" " but the ironic found has a minimum microversion" " of {found}".format(needed=needed, found=self._join_ksa_version( endpoint_data.min_microversion))) if endpoint_data.max_microversion[1] < int(needed[-1]): raise exc.OpenStackCloudException( "shade needs an ironic that supports microversion {needed}" " but the ironic found has a maximum microversion" " of {found}".format(needed=needed, found=self._join_ksa_version( endpoint_data.max_microversion))) return self._create_legacy_client( 'ironic', 'baremetal', deprecated=False, module_name='ironicclient.client.Client', os_ironic_api_version=self._get_legacy_ironic_microversion())
def _get_host(cloud, host): hyps = cloud.nova_client.hypervisors.list() entities = [ x for x in hyps if x.id == host or x.hypervisor_hostname == host or x.service['host'] == host ] if not entities: return None if len(entities) > 1: raise exc.OpenStackCloudException("Multiple matches found for %s" % host) return entities[0]
def read_url_content(url): try: # TODO(mordred) Use requests content = request.urlopen(url).read() except error.URLError: raise exc.OpenStackCloudException('Could not fetch contents for %s' % url) if content: try: content.decode('utf-8') except ValueError: content = base64.encodestring(content) return content
def test_register_machine_port_create_failed(self, mock_client): class fake_node: uuid = "00000000-0000-0000-0000-000000000000" provision_state = "available" resevation = None last_error = None nics = [{'mac': '00:00:00:00:00:00'}] mock_client.node.create.return_value = fake_node mock_client.port.create.side_effect = ( exc.OpenStackCloudException("Error")) self.assertRaises(exc.OpenStackCloudException, self.op_cloud.register_machine, nics) self.assertTrue(mock_client.node.create.called) self.assertTrue(mock_client.port.create.called) self.assertTrue(mock_client.node.delete.called)
def operator_cloud(config=None, strict=False, app_name=None, app_version=None, use_direct_get=False, **kwargs): if not config: config = _get_openstack_config(app_name, app_version) try: cloud_config = config.get_one_cloud(**kwargs) except keystoneauth1.exceptions.auth_plugins.NoMatchingPlugin as e: raise exc.OpenStackCloudException( "Invalid cloud configuration: {exc}".format(exc=str(e))) return OperatorCloud(cloud_config=cloud_config, strict=strict, use_direct_get=use_direct_get)
def _get_entity(cloud, resource, name_or_id, filters, **kwargs): """Return a single entity from the list returned by a given method. :param object cloud: The controller class (Example: the main OpenStackCloud object) . :param string or callable resource: The string that identifies the resource to use to lookup the get_<>_by_id or search_<resource>s methods(Example: network) or a callable to invoke. :param string name_or_id: The name or ID of the entity being filtered or an object or dict. If this is an object/dict with an 'id' attr/key, we return it and bypass resource lookup. :param filters: A dictionary of meta data to use for further filtering. OR A string containing a jmespath expression for further filtering. Example:: "[?last_name==`Smith`] | [?other.gender]==`Female`]" """ # Sometimes in the control flow of shade, we already have an object # fetched. Rather than then needing to pull the name or id out of that # object, pass it in here and rely on caching to prevent us from making # an additional call, it's simple enough to test to see if we got an # object and just short-circuit return it. if (hasattr(name_or_id, 'id') or (isinstance(name_or_id, dict) and 'id' in name_or_id)): return name_or_id # If a uuid is passed short-circuit it calling the # get_<resorce_name>_by_id method if getattr(cloud, 'use_direct_get', False) and _is_uuid_like(name_or_id): get_resource = getattr(cloud, 'get_%s_by_id' % resource, None) if get_resource: return get_resource(name_or_id) search = resource if callable(resource) else getattr( cloud, 'search_%ss' % resource, None) if search: entities = search(name_or_id, filters, **kwargs) if entities: if len(entities) > 1: raise exc.OpenStackCloudException( "Multiple matches found for %s" % name_or_id) return entities[0] return None