def startup_sanity_check(): if (not cfg.CONF.stack_user_domain_id and not cfg.CONF.stack_user_domain_name): # FIXME(shardy): Legacy fallback for folks using old heat.conf # files which lack domain configuration LOG.warn( _LW('stack_user_domain_id or stack_user_domain_name not ' 'set in heat.conf falling back to using default')) else: domain_admin_user = cfg.CONF.stack_domain_admin domain_admin_password = cfg.CONF.stack_domain_admin_password if not (domain_admin_user and domain_admin_password): raise exception.Error( _('heat.conf misconfigured, cannot ' 'specify "stack_user_domain_id" or ' '"stack_user_domain_name" without ' '"stack_domain_admin" and ' '"stack_domain_admin_password"')) auth_key_len = len(cfg.CONF.auth_encryption_key) if auth_key_len in (16, 24): LOG.warn(_LW('Please update auth_encryption_key to be 32 characters.')) elif auth_key_len != 32: raise exception.Error( _('heat.conf misconfigured, auth_encryption_key ' 'must be 32 characters'))
def refresh_server(self, server): """Refresh server's attributes. Also log warnings for non-critical API errors. """ try: server.get() except exceptions.OverLimit as exc: LOG.warning( _LW("Server %(name)s (%(id)s) received an OverLimit " "response during server.get(): %(exception)s"), { 'name': server.name, 'id': server.id, 'exception': exc }) except exceptions.ClientException as exc: if ((getattr(exc, 'http_status', getattr(exc, 'code', None)) in (500, 503))): LOG.warning( _LW('Server "%(name)s" (%(id)s) received the ' 'following exception during server.get(): ' '%(exception)s'), { 'name': server.name, 'id': server.id, 'exception': exc }) else: raise
def _validate_type(self, attrib, value): if attrib.schema.type == attrib.schema.STRING: if not isinstance(value, six.string_types): LOG.warn( _LW("Attribute %(name)s is not of type %(att_type)s"), {"name": attrib.name, "att_type": attrib.schema.STRING}, ) elif attrib.schema.type == attrib.schema.LIST: if not isinstance(value, collections.Sequence) or isinstance(value, six.string_types): LOG.warn( _LW("Attribute %(name)s is not of type %(att_type)s"), {"name": attrib.name, "att_type": attrib.schema.LIST}, ) elif attrib.schema.type == attrib.schema.MAP: if not isinstance(value, collections.Mapping): LOG.warn( _LW("Attribute %(name)s is not of type %(att_type)s"), {"name": attrib.name, "att_type": attrib.schema.MAP}, ) elif attrib.schema.type == attrib.schema.INTEGER: if not isinstance(value, int): LOG.warn( _LW("Attribute %(name)s is not of type %(att_type)s"), {"name": attrib.name, "att_type": attrib.schema.INTEGER}, )
def delete_stack_domain_project(self, project_id): if not self.stack_domain: # FIXME(shardy): Legacy fallback for folks using old heat.conf # files which lack domain configuration return # If stacks are created before configuring the heat domain, they # exist in the default domain, in the user's project, which we # do *not* want to delete! However, if the keystone v3cloudsample # policy is used, it's possible that we'll get Forbidden when trying # to get the project, so again we should do nothing try: project = self.domain_admin_client.projects.get(project=project_id) except kc_exception.NotFound: return except kc_exception.Forbidden: LOG.warning(_LW('Unable to get details for project %s, ' 'not deleting'), project_id) return if project.domain_id != self.stack_domain_id: LOG.warning(_LW('Not deleting non heat-domain project')) return try: project.delete() except kc_exception.NotFound: pass
def _validate_type(self, attrib, value): if attrib.schema.type == attrib.schema.STRING: if not isinstance(value, six.string_types): LOG.warning(_LW("Attribute %(name)s is not of type " "%(att_type)s"), {'name': attrib.name, 'att_type': attrib.schema.STRING}) elif attrib.schema.type == attrib.schema.LIST: if (not isinstance(value, collections.Sequence) or isinstance(value, six.string_types)): LOG.warning(_LW("Attribute %(name)s is not of type " "%(att_type)s"), {'name': attrib.name, 'att_type': attrib.schema.LIST}) elif attrib.schema.type == attrib.schema.MAP: if not isinstance(value, collections.Mapping): LOG.warning(_LW("Attribute %(name)s is not of type " "%(att_type)s"), {'name': attrib.name, 'att_type': attrib.schema.MAP}) elif attrib.schema.type == attrib.schema.INTEGER: if not isinstance(value, int): LOG.warning(_LW("Attribute %(name)s is not of type " "%(att_type)s"), {'name': attrib.name, 'att_type': attrib.schema.INTEGER}) elif attrib.schema.type == attrib.schema.BOOLEAN: try: strutils.bool_from_string(value, strict=True) except ValueError: LOG.warning(_LW("Attribute %(name)s is not of type " "%(att_type)s"), {'name': attrib.name, 'att_type': attrib.schema.BOOLEAN})
def _register_info(self, path, info): """Place the new info in the correct location in the registry. :param path: a list of keys ['resources', 'my_srv', 'OS::Nova::Server'] """ descriptive_path = '/'.join(path) name = path[-1] # create the structure if needed registry = self._registry for key in path[:-1]: if key not in registry: registry[key] = {} registry = registry[key] if info is None: if name.endswith('*'): # delete all matching entries. for res_name, reg_info in list(registry.items()): if (isinstance(reg_info, ResourceInfo) and res_name.startswith(name[:-1])): LOG.warning(_LW('Removing %(item)s from %(path)s'), { 'item': res_name, 'path': descriptive_path }) del registry[res_name] else: # delete this entry. LOG.warning(_LW('Removing %(item)s from %(path)s'), { 'item': name, 'path': descriptive_path }) registry.pop(name, None) return if name in registry and isinstance(registry[name], ResourceInfo): if registry[name] == info: return details = { 'path': descriptive_path, 'was': str(registry[name].value), 'now': str(info.value) } LOG.warning(_LW('Changing %(path)s from %(was)s to %(now)s'), details) if isinstance(info, ClassResourceInfo): if info.value.support_status.status != support.SUPPORTED: if info.value.support_status.message is not None: details = { 'name': info.name, 'status': six.text_type(info.value.support_status.status), 'message': six.text_type(info.value.support_status.message) } LOG.warning(_LW('%(name)s is %(status)s. %(message)s'), details) info.user_resource = (self.global_registry is not None) registry[name] = info
def refresh_server(server): ''' Refresh server's attributes and log warnings for non-critical API errors. ''' warnings.warn('nova_utils.refresh_server is deprecated. ' 'Use self.client_plugin("nova").refresh_server') try: server.get() except nova_exceptions.OverLimit as exc: LOG.warn(_LW("Server %(name)s (%(id)s) received an OverLimit " "response during server.get(): %(exception)s"), {'name': server.name, 'id': server.id, 'exception': exc}) except nova_exceptions.ClientException as exc: http_status = (getattr(exc, 'http_status', None) or getattr(exc, 'code', None)) if http_status in (500, 503): LOG.warn(_LW('Server "%(name)s" (%(id)s) received the following ' 'exception during server.get(): %(exception)s'), {'name': server.name, 'id': server.id, 'exception': exc}) else: raise
def refresh_server(server): ''' Refresh server's attributes and log warnings for non-critical API errors. ''' warnings.warn('nova_utils.refresh_server is deprecated. ' 'Use self.client_plugin("nova").refresh_server') try: server.get() except nova_exceptions.OverLimit as exc: LOG.warn(_LW("Server %(name)s (%(id)s) received an OverLimit " "response during server.get(): %(exception)s"), {'name': server.name, 'id': server.id, 'exception': exc}) except nova_exceptions.ClientException as exc: http_status = (getattr(exc, 'http_status', None) or getattr(exc, 'code', None)) if http_status in (500, 503): LOG.warn(_LW('Server "%(name)s" (%(id)s) received the following ' 'exception during server.get(): %(exception)s'), {'name': server.name, 'id': server.id, 'exception': exc}) else: raise
def _validate_type(self, attrib, value): if attrib.schema.type == attrib.schema.STRING: if not isinstance(value, six.string_types): LOG.warning(_LW("Attribute %(name)s is not of type " "%(att_type)s"), {'name': attrib.name, 'att_type': attrib.schema.STRING}) elif attrib.schema.type == attrib.schema.LIST: if (not isinstance(value, collections.Sequence) or isinstance(value, six.string_types)): LOG.warning(_LW("Attribute %(name)s is not of type " "%(att_type)s"), {'name': attrib.name, 'att_type': attrib.schema.LIST}) elif attrib.schema.type == attrib.schema.MAP: if not isinstance(value, collections.Mapping): LOG.warning(_LW("Attribute %(name)s is not of type " "%(att_type)s"), {'name': attrib.name, 'att_type': attrib.schema.MAP}) elif attrib.schema.type == attrib.schema.INTEGER: if not isinstance(value, int): LOG.warning(_LW("Attribute %(name)s is not of type " "%(att_type)s"), {'name': attrib.name, 'att_type': attrib.schema.INTEGER}) elif attrib.schema.type == attrib.schema.BOOLEAN: try: strutils.bool_from_string(value, strict=True) except ValueError: LOG.warning(_LW("Attribute %(name)s is not of type " "%(att_type)s"), {'name': attrib.name, 'att_type': attrib.schema.BOOLEAN})
def delete_stack_domain_project(self, project_id): if not self.stack_domain: # FIXME(shardy): Legacy fallback for folks using old heat.conf # files which lack domain configuration return # If stacks are created before configuring the heat domain, they # exist in the default domain, in the user's project, which we # do *not* want to delete! However, if the keystone v3cloudsample # policy is used, it's possible that we'll get Forbidden when trying # to get the project, so again we should do nothing try: project = self.domain_admin_client.projects.get(project=project_id) except kc_exception.NotFound: return except kc_exception.Forbidden: LOG.warning( _LW('Unable to get details for project %s, ' 'not deleting'), project_id) return if project.domain_id != self.stack_domain_id: LOG.warning(_LW('Not deleting non heat-domain project')) return try: project.delete() except kc_exception.NotFound: pass
def startup_sanity_check(): if not cfg.CONF.stack_user_domain_id and not cfg.CONF.stack_user_domain_name: # FIXME(shardy): Legacy fallback for folks using old heat.conf # files which lack domain configuration LOG.warn( _LW("stack_user_domain_id or stack_user_domain_name not " "set in heat.conf falling back to using default") ) else: domain_admin_user = cfg.CONF.stack_domain_admin domain_admin_password = cfg.CONF.stack_domain_admin_password if not (domain_admin_user and domain_admin_password): raise exception.Error( _( "heat.conf misconfigured, cannot " 'specify "stack_user_domain_id" or ' '"stack_user_domain_name" without ' '"stack_domain_admin" and ' '"stack_domain_admin_password"' ) ) auth_key_len = len(cfg.CONF.auth_encryption_key) if auth_key_len in (16, 24): LOG.warn(_LW("Please update auth_encryption_key to be 32 characters.")) elif auth_key_len != 32: raise exception.Error(_("heat.conf misconfigured, auth_encryption_key " "must be 32 characters"))
def fetch_server(self, server_id): """Fetch fresh server object from Nova. Log warnings and return None for non-critical API errors. Use this method in various ``check_*_complete`` resource methods, where intermittent errors can be tolerated. """ server = None try: server = self.client().servers.get(server_id) except exceptions.OverLimit as exc: LOG.warning(_LW("Received an OverLimit response when " "fetching server (%(id)s) : %(exception)s"), {'id': server_id, 'exception': exc}) except exceptions.ClientException as exc: if ((getattr(exc, 'http_status', getattr(exc, 'code', None)) in (500, 503))): LOG.warning(_LW("Received the following exception when " "fetching server (%(id)s) : %(exception)s"), {'id': server_id, 'exception': exc}) else: raise return server
def fetch_server(self, server_id): """Fetch fresh server object from Nova. Log warnings and return None for non-critical API errors. Use this method in various ``check_*_complete`` resource methods, where intermittent errors can be tolerated. """ server = None try: server = self.client().servers.get(server_id) except exceptions.OverLimit as exc: LOG.warning( _LW("Received an OverLimit response when " "fetching server (%(id)s) : %(exception)s"), { 'id': server_id, 'exception': exc }) except exceptions.ClientException as exc: if ((getattr(exc, 'http_status', getattr(exc, 'code', None)) in (500, 503))): LOG.warning( _LW("Received the following exception when " "fetching server (%(id)s) : %(exception)s"), { 'id': server_id, 'exception': exc }) else: raise return server
def _register_info(self, path, info): """Place the new info in the correct location in the registry. :param path: a list of keys ['resources', 'my_srv', 'OS::Nova::Server'] """ descriptive_path = '/'.join(path) name = path[-1] # create the structure if needed registry = self._registry for key in path[:-1]: if key not in registry: registry[key] = {} registry = registry[key] if info is None: if name.endswith('*'): # delete all matching entries. for res_name, reg_info in list(registry.items()): if (isinstance(reg_info, ResourceInfo) and res_name.startswith(name[:-1])): LOG.warning(_LW('Removing %(item)s from %(path)s'), { 'item': res_name, 'path': descriptive_path}) del registry[res_name] else: # delete this entry. LOG.warning(_LW('Removing %(item)s from %(path)s'), { 'item': name, 'path': descriptive_path}) registry.pop(name, None) return if name in registry and isinstance(registry[name], ResourceInfo): if registry[name] == info: return details = { 'path': descriptive_path, 'was': str(registry[name].value), 'now': str(info.value)} LOG.warning(_LW('Changing %(path)s from %(was)s to %(now)s'), details) if isinstance(info, ClassResourceInfo): if info.value.support_status.status != support.SUPPORTED: if info.value.support_status.message is not None: details = { 'name': info.name, 'status': six.text_type( info.value.support_status.status), 'message': six.text_type( info.value.support_status.message) } LOG.warning(_LW('%(name)s is %(status)s. %(message)s'), details) info.user_resource = (self.global_registry is not None) registry[name] = info
def check_stack_watches(self, sid): # Retrieve the stored credentials & create context # Require tenant_safe=False to the stack_get to defeat tenant # scoping otherwise we fail to retrieve the stack LOG.debug("Periodic watcher task for stack %s" % sid) admin_context = context.get_admin_context() db_stack = stack_object.Stack.get_by_id(admin_context, sid, tenant_safe=False, eager_load=True) if not db_stack: LOG.error(_LE("Unable to retrieve stack %s for periodic task"), sid) return stk = stack.Stack.load(admin_context, stack=db_stack, use_stored_context=True) # recurse into any nested stacks. children = stack_object.Stack.get_all_by_owner_id(admin_context, sid) for child in children: self.check_stack_watches(child.id) # Get all watchrules for this stack and evaluate them try: wrs = watch_rule_object.WatchRule.get_all_by_stack(admin_context, sid) except Exception as ex: LOG.warn(_LW("periodic_task db error watch rule removed? %(ex)s"), ex) return def run_alarm_action(stk, actions, details): for action in actions: action(details=details) for res in six.itervalues(stk): res.metadata_update() for wr in wrs: rule = watchrule.WatchRule.load(stk.context, watch=wr) actions = rule.evaluate() if actions: self.thread_group_mgr.start(sid, run_alarm_action, stk, actions, rule.get_details())
def metadata_update(self, new_metadata=None): ''' No-op for resources which don't explicitly override this method ''' if new_metadata: LOG.warn(_LW("Resource %s does not implement metadata update"), self.name)
def handle_signal(self, details=None): if self.action in (self.SUSPEND, self.DELETE): msg = _('Cannot signal resource during %s') % self.action raise Exception(msg) LOG.warn(_LW('Signaled resource (Type "%(type)s") %(details)s'), {'type': self.type(), 'details': details})
def available_resource_mapping(): if DOCKER_INSTALLED: return resource_mapping() else: LOG.warning(_LW("Docker plug-in loaded, but docker lib " "not installed.")) return {}
def format_metric_data(d, fil=None): """Reformat engine output into the AWS "Metric" format. Takes an optional filter dict, which is traversed so a metric dict is only returned if all keys match the filter dict. """ fil = fil or {} dimensions = [ {'AlarmName': d[rpc_api.WATCH_DATA_ALARM]}, {'Timestamp': d[rpc_api.WATCH_DATA_TIME]} ] for key in d[rpc_api.WATCH_DATA]: dimensions.append({key: d[rpc_api.WATCH_DATA][key]}) newdims = self._reformat_dimensions(dimensions) result = { 'MetricName': d[rpc_api.WATCH_DATA_METRIC], 'Dimensions': newdims, 'Namespace': d[rpc_api.WATCH_DATA_NAMESPACE], } for f in fil: try: value = result[f] if value != fil[f]: # Filter criteria not met, return None return except KeyError: LOG.warn(_LW("Invalid filter key %s, ignoring"), f) return result
def trusts_auth_plugin(self): if self._trusts_auth_plugin: return self._trusts_auth_plugin self._trusts_auth_plugin = ks_loading.load_auth_from_conf_options( cfg.CONF, TRUSTEE_CONF_GROUP, trust_id=self.trust_id) if self._trusts_auth_plugin: return self._trusts_auth_plugin LOG.warning(_LW('Using the keystone_authtoken user as the heat ' 'trustee user directly is deprecated. Please add the ' 'trustee credentials you need to the %s section of ' 'your heat.conf file.') % TRUSTEE_CONF_GROUP) cfg.CONF.import_group('keystone_authtoken', 'keystonemiddleware.auth_token') trustee_user_domain = 'default' if 'user_domain_id' in cfg.CONF.keystone_authtoken: trustee_user_domain = cfg.CONF.keystone_authtoken.user_domain_id self._trusts_auth_plugin = generic.Password( username=cfg.CONF.keystone_authtoken.admin_user, password=cfg.CONF.keystone_authtoken.admin_password, user_domain_id=trustee_user_domain, auth_url=self.keystone_v3_endpoint, trust_id=self.trust_id) return self._trusts_auth_plugin
def _index(self, req, tenant_safe=True): filter_whitelist = { 'status': 'mixed', 'name': 'mixed', 'action': 'mixed', 'tenant': 'mixed', 'username': '******', 'owner_id': 'mixed', } whitelist = { 'limit': 'single', 'marker': 'single', 'sort_dir': 'single', 'sort_keys': 'multi', 'show_deleted': 'single', 'show_nested': 'single', } params = util.get_allowed_params(req.params, whitelist) filter_params = util.get_allowed_params(req.params, filter_whitelist) show_deleted = False if rpc_api.PARAM_SHOW_DELETED in params: params[rpc_api.PARAM_SHOW_DELETED] = param_utils.extract_bool( params[rpc_api.PARAM_SHOW_DELETED]) show_deleted = params[rpc_api.PARAM_SHOW_DELETED] show_nested = False if rpc_api.PARAM_SHOW_NESTED in params: params[rpc_api.PARAM_SHOW_NESTED] = param_utils.extract_bool( params[rpc_api.PARAM_SHOW_NESTED]) show_nested = params[rpc_api.PARAM_SHOW_NESTED] # get the with_count value, if invalid, raise ValueError with_count = False if req.params.get('with_count'): with_count = param_utils.extract_bool(req.params.get('with_count')) if not filter_params: filter_params = None stacks = self.rpc_client.list_stacks(req.context, filters=filter_params, tenant_safe=tenant_safe, **params) count = None if with_count: try: # Check if engine has been updated to a version with # support to count_stacks before trying to use it. count = self.rpc_client.count_stacks(req.context, filters=filter_params, tenant_safe=tenant_safe, show_deleted=show_deleted, show_nested=show_nested) except AttributeError as exc: LOG.warn(_LW("Old Engine Version: %s") % exc) return stacks_view.collection(req, stacks=stacks, count=count, tenant_safe=tenant_safe)
def format_metric_data(d, fil=None): """Reformat engine output into the AWS "Metric" format. Takes an optional filter dict, which is traversed so a metric dict is only returned if all keys match the filter dict. """ fil = fil or {} dimensions = [{ 'AlarmName': d[rpc_api.WATCH_DATA_ALARM] }, { 'Timestamp': d[rpc_api.WATCH_DATA_TIME] }] for key in d[rpc_api.WATCH_DATA]: dimensions.append({key: d[rpc_api.WATCH_DATA][key]}) newdims = self._reformat_dimensions(dimensions) result = { 'MetricName': d[rpc_api.WATCH_DATA_METRIC], 'Dimensions': newdims, 'Namespace': d[rpc_api.WATCH_DATA_NAMESPACE], } for f in fil: try: value = result[f] if value != fil[f]: # Filter criteria not met, return None return except KeyError: LOG.warning(_LW("Invalid filter key %s, ignoring"), f) return result
def handle_signal(self, details=None): if self.action in (self.SUSPEND, self.DELETE): msg = _('Cannot signal resource during %s') % self.action raise Exception(msg) LOG.warn(_LW('Signaled resource (Type "%(type)s") %(details)s'), {'type': self.type(), 'details': details})
def trusts_auth_plugin(self): if self._trusts_auth_plugin: return self._trusts_auth_plugin self._trusts_auth_plugin = auth.load_from_conf_options( cfg.CONF, TRUSTEE_CONF_GROUP, trust_id=self.trust_id) if self._trusts_auth_plugin: return self._trusts_auth_plugin LOG.warn(_LW('Using the keystone_authtoken user as the heat ' 'trustee user directly is deprecated. Please add the ' 'trustee credentials you need to the %s section of ' 'your heat.conf file.') % TRUSTEE_CONF_GROUP) cfg.CONF.import_group('keystone_authtoken', 'keystonemiddleware.auth_token') self._trusts_auth_plugin = v3.Password( username=cfg.CONF.keystone_authtoken.admin_user, password=cfg.CONF.keystone_authtoken.admin_password, user_domain_id='default', auth_url=self.keystone_v3_endpoint, trust_id=self.trust_id) return self._trusts_auth_plugin
def _set_param_stackid(self): ''' Update self.parameters with the current ARN which is then provided via the Parameters class as the StackId pseudo parameter ''' if not self.parameters.set_stack_id(self.identifier()): LOG.warn(_LW("Unable to set parameters StackId identifier"))
def check_update_complete(self, updates): instance = self.client().instances.get(self.resource_id) if instance.status in self.BAD_STATUSES: raise exception.ResourceInError( resource_status=instance.status, status_reason=self.TROVE_STATUS_REASON.get(instance.status, _("Unknown")), ) if updates: if instance.status != self.ACTIVE: dmsg = "Instance is in status %(now)s. Waiting on status" " %(stat)s" LOG.debug(dmsg % {"now": instance.status, "stat": self.ACTIVE}) return False try: return ( self._update_name(instance, updates.get(self.NAME)) and self._update_flavor(instance, updates.get(self.FLAVOR)) and self._update_size(instance, updates.get(self.SIZE)) and self._update_databases(instance, updates.get(self.DATABASES)) and self._update_users(instance, updates.get(self.USERS)) ) except Exception as exc: if self.client_plugin().is_client_exception(exc): # the instance could have updated between the time # we retrieve it and try to update it so check again if self.client_plugin().is_over_limit(exc): LOG.debug("API rate limit: %(ex)s. Retrying." % {"ex": six.text_type(exc)}) return False if "No change was requested" in six.text_type(exc): LOG.warning(_LW("Unexpected instance state change " "during update. Retrying.")) return False raise exc return True
def from_db_object(context, tpl, db_tpl): for field in tpl.fields: tpl[field] = db_tpl[field] tpl.environment = copy.deepcopy(tpl.environment) # If any of the parameters were encrypted, then decrypt them if (tpl.environment is not None and env_fmt.ENCRYPTED_PARAM_NAMES in tpl.environment): parameters = tpl.environment[env_fmt.PARAMETERS] encrypted_param_names = tpl.environment[ env_fmt.ENCRYPTED_PARAM_NAMES] for param_name in encrypted_param_names: if (isinstance(parameters[param_name], (list, tuple)) and len(parameters[param_name]) == 2): method, enc_value = parameters[param_name] value = crypt.decrypt(method, enc_value) else: value = parameters[param_name] LOG.warning(_LW( 'Encountered already-decrypted data while attempting ' 'to decrypt parameter %s. Please file a Heat bug so ' 'this can be fixed.'), param_name) parameters[param_name] = value tpl.environment[env_fmt.PARAMETERS] = parameters tpl._context = context tpl.obj_reset_changes() return tpl
def get_server(self, server): try: return self.client().servers.get(server) except exceptions.NotFound as ex: LOG.warn(_LW('Server (%(server)s) not found: %(ex)s'), {'server': server, 'ex': ex}) raise exception.ServerNotFound(server=server)
def _set_param_stackid(self): ''' Update self.parameters with the current ARN which is then provided via the Parameters class as the StackId pseudo parameter ''' if not self.parameters.set_stack_id(self.identifier()): LOG.warn(_LW("Unable to set parameters StackId identifier"))
def metadata_update(self, new_metadata=None): ''' No-op for resources which don't explicitly override this method ''' if new_metadata: LOG.warn(_LW("Resource %s does not implement metadata update"), self.name)
def load(cls, context, watch_name=None, watch=None): """Load the watchrule object. The object can be loaded either from the DB by name or from an existing DB object. """ if watch is None: try: watch = watch_rule_objects.WatchRule.get_by_name(context, watch_name) except Exception as ex: LOG.warning(_LW('WatchRule.load (%(watch_name)s) db error ' '%(ex)s'), {'watch_name': watch_name, 'ex': ex}) if watch is None: raise exception.EntityNotFound(entity='Watch Rule', name=watch_name) else: return cls(context=context, watch_name=watch.name, rule=watch.rule, stack_id=watch.stack_id, state=watch.state, wid=watch.id, watch_data=watch.watch_data, last_evaluated=watch.last_evaluated)
def _get_username(self, username): if (len(username) > 64): LOG.warning( _LW("Truncating the username %s to the last 64 " "characters."), username) # get the last 64 characters of the username return username[-64:]
def handle_create(self): """Add a floating IP address to a server.""" if self.properties[self.EIP]: server = self.nova().servers.get(self.properties[self.INSTANCE_ID]) server.add_floating_ip(self.properties[self.EIP]) self.resource_id_set(self.properties[self.EIP]) LOG.debug('ElasticIpAssociation ' '%(instance)s.add_floating_ip(%(eip)s)', {'instance': self.properties[self.INSTANCE_ID], 'eip': self.properties[self.EIP]}) elif self.properties[self.ALLOCATION_ID]: ni_id = self.properties[self.NETWORK_INTERFACE_ID] instance_id = self.properties[self.INSTANCE_ID] port_id, port_rsrc = self._get_port_info(ni_id, instance_id) if not port_id or not port_rsrc: LOG.warn(_LW('Skipping association, resource not specified')) return float_id = self.properties[self.ALLOCATION_ID] network_id = port_rsrc['network_id'] self._neutron_add_gateway_router(float_id, network_id) self._neutron_update_floating_ip(float_id, port_id) self.resource_id_set(float_id)
def get_server(self, server): try: return self.client().servers.get(server) except exceptions.NotFound as ex: LOG.warn(_LW('Server (%(server)s) not found: %(ex)s'), {'server': server, 'ex': ex}) raise exception.ServerNotFound(server=server)
def load(cls, context, watch_name=None, watch=None): """Load the watchrule object. Loading object either by name or via an existing DB object. """ if watch is None: try: watch = watch_rule_objects.WatchRule.get_by_name( context, watch_name) except Exception as ex: LOG.warn( _LW('WatchRule.load (%(watch_name)s) db error ' '%(ex)s'), { 'watch_name': watch_name, 'ex': ex }) if watch is None: raise exception.WatchRuleNotFound(watch_name=watch_name) else: return cls(context=context, watch_name=watch.name, rule=watch.rule, stack_id=watch.stack_id, state=watch.state, wid=watch.id, watch_data=watch.watch_data, last_evaluated=watch.last_evaluated)
def handle_create(self): """Add a floating IP address to a server.""" if self.properties[self.EIP]: server = self.nova().servers.get(self.properties[self.INSTANCE_ID]) server.add_floating_ip(self.properties[self.EIP]) self.resource_id_set(self.properties[self.EIP]) LOG.debug('ElasticIpAssociation ' '%(instance)s.add_floating_ip(%(eip)s)', {'instance': self.properties[self.INSTANCE_ID], 'eip': self.properties[self.EIP]}) elif self.properties[self.ALLOCATION_ID]: ni_id = self.properties[self.NETWORK_INTERFACE_ID] instance_id = self.properties[self.INSTANCE_ID] port_id, port_rsrc = self._get_port_info(ni_id, instance_id) if not port_id or not port_rsrc: LOG.warn(_LW('Skipping association, resource not specified')) return float_id = self.properties[self.ALLOCATION_ID] network_id = port_rsrc['network_id'] self._neutron_add_gateway_router(float_id, network_id) self._neutron_update_floating_ip(float_id, port_id) self.resource_id_set(float_id)
def set_watch_state(self, state): """Temporarily set the watch state. :returns: list of functions to be scheduled in the stack ThreadGroup for the specified state. """ if state not in self.WATCH_STATES: raise ValueError(_('Unknown watch state %s') % state) actions = [] if state != self.state: actions = self.rule_actions(state) if actions: LOG.debug("Overriding state %(self_state)s for watch " "%(name)s with %(state)s" % { 'self_state': self.state, 'name': self.name, 'state': state }) else: LOG.warn( _LW("Unable to override state %(state)s for " "watch %(name)s"), { 'state': self.state, 'name': self.name }) return actions
def _resolve_attribute(self, key): parsed = list(urlparse.urlparse(self.client().url)) if key == self.DOMAIN_NAME: return parsed[1].split(':')[0] elif key == self.WEBSITE_URL: return '%s://%s%s/%s' % (parsed[0], parsed[1], parsed[2], self.resource_id) elif key == self.ROOT_URL: return '%s://%s%s' % (parsed[0], parsed[1], parsed[2]) elif self.resource_id and key in (self.OBJECT_COUNT, self.BYTES_USED, self.HEAD_CONTAINER): try: headers = self.client().head_container(self.resource_id) except Exception as ex: if self.client_plugin().is_client_exception(ex): LOG.warn(_LW("Head container failed: %s"), ex) return None raise else: if key == self.OBJECT_COUNT: return headers['x-container-object-count'] elif key == self.BYTES_USED: return headers['x-container-bytes-used'] elif key == self.HEAD_CONTAINER: return headers
def _resolve_attribute(self, key): parsed = list(urlparse.urlparse(self.swift().url)) if key == self.DOMAIN_NAME: return parsed[1].split(':')[0] elif key == self.WEBSITE_URL: return '%s://%s%s/%s' % (parsed[0], parsed[1], parsed[2], self.resource_id) elif key == self.ROOT_URL: return '%s://%s%s' % (parsed[0], parsed[1], parsed[2]) elif self.resource_id and key in ( self.OBJECT_COUNT, self.BYTES_USED, self.HEAD_CONTAINER): try: headers = self.swift().head_container(self.resource_id) except Exception as ex: if self.client_plugin().is_client_exception(ex): LOG.warn(_LW("Head container failed: %s"), ex) return None raise else: if key == self.OBJECT_COUNT: return headers['x-container-object-count'] elif key == self.BYTES_USED: return headers['x-container-bytes-used'] elif key == self.HEAD_CONTAINER: return headers
def __init__(self, context): # If a trust_id is specified in the context, we immediately # authenticate so we can populate the context with a trust token # otherwise, we delay client authentication until needed to avoid # unnecessary calls to keystone. # # Note that when you obtain a token using a trust, it cannot be # used to reauthenticate and get another token, so we have to # get a new trust-token even if context.auth_token is set. # # - context.auth_url is expected to contain a versioned keystone # path, we will work with either a v2.0 or v3 path self.context = context self._client = None self._admin_client = None self._domain_admin_client = None self.session = session.Session.construct(self._ssl_options()) if self.context.auth_url: self.v3_endpoint = self.context.auth_url.replace('v2.0', 'v3') else: # Import auth_token to have keystone_authtoken settings setup. importutils.import_module('keystonemiddleware.auth_token') self.v3_endpoint = cfg.CONF.keystone_authtoken.auth_uri.replace( 'v2.0', 'v3') if self.context.trust_id: # Create a client with the specified trust_id, this # populates self.context.auth_token with a trust-scoped token self._client = self._v3_client_init() # The stack domain user ID should be set in heat.conf # It can be created via python-openstackclient # openstack --os-identity-api-version=3 domain create heat # If the domain is specified, then you must specify a domain # admin user. If no domain is specified, we fall back to # legacy behavior with warnings. self._stack_domain_is_id = True self._stack_domain_id = None self.stack_domain = cfg.CONF.stack_user_domain_id if not self.stack_domain and cfg.CONF.stack_user_domain_name: self.stack_domain = cfg.CONF.stack_user_domain_name self._stack_domain_is_id = False self.domain_admin_user = cfg.CONF.stack_domain_admin self.domain_admin_password = cfg.CONF.stack_domain_admin_password if self.stack_domain: if not (self.domain_admin_user and self.domain_admin_password): raise exception.Error( _('heat.conf misconfigured, cannot ' 'specify "stack_user_domain_id" or ' '"stack_user_domain_name" without ' '"stack_domain_admin" and ' '"stack_domain_admin_password"')) else: LOG.warn( _LW('stack_user_domain_id or stack_user_domain_name not ' 'set in heat.conf falling back to using default')) LOG.debug('Using stack domain %s' % self.stack_domain)
def _index(self, req, tenant_safe=True): filter_whitelist = { 'status': 'mixed', 'name': 'mixed', 'action': 'mixed', 'tenant': 'mixed', 'username': '******', 'owner_id': 'mixed', } whitelist = { 'limit': 'single', 'marker': 'single', 'sort_dir': 'single', 'sort_keys': 'multi', 'show_deleted': 'single', 'show_nested': 'single', } params = util.get_allowed_params(req.params, whitelist) filter_params = util.get_allowed_params(req.params, filter_whitelist) show_deleted = False if engine_api.PARAM_SHOW_DELETED in params: params[engine_api.PARAM_SHOW_DELETED] = param_utils.extract_bool( params[engine_api.PARAM_SHOW_DELETED]) show_deleted = params[engine_api.PARAM_SHOW_DELETED] show_nested = False if engine_api.PARAM_SHOW_NESTED in params: params[engine_api.PARAM_SHOW_NESTED] = param_utils.extract_bool( params[engine_api.PARAM_SHOW_NESTED]) show_nested = params[engine_api.PARAM_SHOW_NESTED] # get the with_count value, if invalid, raise ValueError with_count = False if req.params.get('with_count'): with_count = param_utils.extract_bool( req.params.get('with_count')) if not filter_params: filter_params = None stacks = self.rpc_client.list_stacks(req.context, filters=filter_params, tenant_safe=tenant_safe, **params) count = None if with_count: try: # Check if engine has been updated to a version with # support to count_stacks before trying to use it. count = self.rpc_client.count_stacks(req.context, filters=filter_params, tenant_safe=tenant_safe, show_deleted=show_deleted, show_nested=show_nested) except AttributeError as exc: LOG.warn(_LW("Old Engine Version: %s") % exc) return stacks_view.collection(req, stacks=stacks, count=count, tenant_safe=tenant_safe)
def log_fail_msg(manager, entrypoint, exception): LOG.warning( _LW('Encountered exception while loading %(module_name)s: ' '"%(message)s". Not using %(name)s.'), { 'module_name': entrypoint.module_name, 'message': exception.message, 'name': entrypoint.name })
def _show_resource(self): method_name = 'get_' + self.entity try: client_method = getattr(self.client(), method_name) res_info = client_method(self.resource_id) return res_info.to_dict() except AttributeError as ex: LOG.warning(_LW("No method to get the resource: %s"), ex)
def resource_id_set(self, inst): self.resource_id = inst if self.id is not None: try: rs = db_api.resource_get(self.context, self.id) rs.update_and_save({'nova_instance': self.resource_id}) except Exception as ex: LOG.warn(_LW('db error %s'), ex)
def resource_id_set(self, inst): self.resource_id = inst if self.id is not None: try: rs = resource_objects.Resource.get_obj(self.context, self.id) rs.update_and_save({'nova_instance': self.resource_id}) except Exception as ex: LOG.warn(_LW('db error %s'), ex)
def network(self): if self.resource_id and not self._network: try: self._network = self.cloud_networks().get(self.resource_id) except NotFound: LOG.warn(_LW("Could not find network %s but resource id is" " set."), self.resource_id) return self._network
def network(self): if self.resource_id and not self._network: try: self._network = self.cloud_networks().get(self.resource_id) except NotFound: LOG.warning(_LW("Could not find network %s but resource id is" " set."), self.resource_id) return self._network
def available_resource_mapping(): if DOCKER_INSTALLED: return resource_mapping() else: LOG.warning( _LW("Docker plug-in loaded, but docker lib " "not installed.")) return {}
def enable_stack_domain_user(self, user_id, project_id): if not self.stack_domain: # FIXME(shardy): Legacy fallback for folks using old heat.conf # files which lack domain configuration LOG.warn(_LW('Falling back to legacy non-domain enable, ' 'configure domain in heat.conf')) return self.enable_stack_user(user_id) self._check_stack_domain_user(user_id, project_id, 'enable') self.domain_admin_client.users.update(user=user_id, enabled=True)
def _get_signed_url(self, signal_type=SIGNAL): """Create properly formatted and pre-signed URL. This uses the created user for the credentials. See boto/auth.py::QuerySignatureV2AuthHandler :param signal_type: either WAITCONDITION or SIGNAL. """ stored = self.data().get('ec2_signed_url') if stored is not None: return stored access_key = self.data().get('access_key') secret_key = self.data().get('secret_key') if not access_key or not secret_key: LOG.warn(_LW('Cannot generate signed url, ' 'no stored access/secret key')) return config_url = cfg.CONF.heat_waitcondition_server_url if config_url: signal_url = config_url.replace('/waitcondition', signal_type) else: heat_client_plugin = self.stack.clients.client_plugin('heat') endpoint = heat_client_plugin.get_heat_cfn_url() signal_url = ''.join([endpoint, signal_type]) host_url = urlparse.urlparse(signal_url) path = self.identifier().arn_url_path() # Note the WSGI spec apparently means that the webob request we end up # processing in the CFN API (ec2token.py) has an unquoted path, so we # need to calculate the signature with the path component unquoted, but # ensure the actual URL contains the quoted version... unquoted_path = urlparse.unquote(host_url.path + path) request = {'host': host_url.netloc.lower(), 'verb': SIGNAL_VERB[signal_type], 'path': unquoted_path, 'params': {'SignatureMethod': 'HmacSHA256', 'SignatureVersion': '2', 'AWSAccessKeyId': access_key, 'Timestamp': self.created_time.strftime("%Y-%m-%dT%H:%M:%SZ") }} # Sign the request signer = ec2_utils.Ec2Signer(secret_key) request['params']['Signature'] = signer.generate(request) qs = urlparse.urlencode(request['params']) url = "%s%s?%s" % (signal_url.lower(), path, qs) self.data_set('ec2_signed_url', url) return url
def _remove_children(self, pid): if pid in self.children: self.children.remove(pid) LOG.info(_LI('Removed dead child %s'), pid) elif pid in self.stale_children: self.stale_children.remove(pid) LOG.info(_LI('Removed stale child %s'), pid) else: LOG.warning(_LW('Unrecognised child %s'), pid)
def _remove_children(self, pid): if pid in self.children: self.children.remove(pid) LOG.info(_LI('Removed dead child %s'), pid) elif pid in self.stale_children: self.stale_children.remove(pid) LOG.info(_LI('Removed stale child %s'), pid) else: LOG.warning(_LW('Unrecognised child %s'), pid)
def enable_stack_domain_user(self, user_id, project_id): if not self.stack_domain: # FIXME(shardy): Legacy fallback for folks using old heat.conf # files which lack domain configuration LOG.warn( _LW('Falling back to legacy non-domain enable, ' 'configure domain in heat.conf')) return self.enable_stack_user(user_id) self._check_stack_domain_user(user_id, project_id, 'enable') self.domain_admin_client.users.update(user=user_id, enabled=True)
def release(self, stack_id): """Release a stack lock.""" # Only the engine that owns the lock will be releasing it. result = db_api.stack_lock_release(stack_id, self.engine_id) if result is True: LOG.warn(_LW("Lock was already released on stack %s!"), stack_id) else: LOG.debug("Engine %(engine)s released lock on stack " "%(stack)s" % {'engine': self.engine_id, 'stack': stack_id})
def _stop_traversal(stack): old_trvsl = stack.current_traversal updated = _update_current_traversal(stack) if not updated: LOG.warning(_LW("Failed to update stack %(name)s with new " "traversal, aborting stack cancel"), {'name': stack.name}) return reason = 'Stack %(action)s cancelled' % {'action': stack.action} updated = stack.state_set(stack.action, stack.FAILED, reason) if not updated: LOG.warning(_LW("Failed to update stack %(name)s status " "to %(action)s_%(state)s"), {'name': stack.name, 'action': stack.action, 'state': stack.FAILED}) return sync_point.delete_all(stack.context, stack.id, old_trvsl)
def _stop_traversal(stack): old_trvsl = stack.current_traversal updated = _update_current_traversal(stack) if not updated: LOG.warning(_LW("Failed to update stack %(name)s with new " "traversal, aborting stack cancel"), {'name': stack.name}) return reason = 'Stack %(action)s cancelled' % {'action': stack.action} updated = stack.state_set(stack.action, stack.FAILED, reason) if not updated: LOG.warning(_LW("Failed to update stack %(name)s status " "to %(action)s_%(state)s"), {'name': stack.name, 'action': stack.action, 'state': stack.FAILED}) return sync_point.delete_all(stack.context, stack.id, old_trvsl)
def release(self, stack_id): """Release a stack lock.""" # Only the engine that owns the lock will be releasing it. result = db_api.stack_lock_release(stack_id, self.engine_id) if result is True: LOG.warn(_LW("Lock was already released on stack %s!"), stack_id) else: LOG.debug("Engine %(engine)s released lock on stack " "%(stack)s" % {'engine': self.engine_id, 'stack': stack_id})
def server_to_ipaddress(self, server): """Return the server's IP address, fetching it from Nova.""" try: server = self.client().servers.get(server) except exceptions.NotFound as ex: LOG.warning(_LW("Instance (%(server)s) not found: %(ex)s"), {"server": server, "ex": ex}) else: for n in sorted(server.networks, reverse=True): if len(server.networks[n]) > 0: return server.networks[n][0]
def __init__(self, context): # If a trust_id is specified in the context, we immediately # authenticate so we can populate the context with a trust token # otherwise, we delay client authentication until needed to avoid # unnecessary calls to keystone. # # Note that when you obtain a token using a trust, it cannot be # used to reauthenticate and get another token, so we have to # get a new trust-token even if context.auth_token is set. # # - context.auth_url is expected to contain a versioned keystone # path, we will work with either a v2.0 or v3 path self.context = context self._client = None self._admin_client = None self._domain_admin_client = None if self.context.auth_url: self.v3_endpoint = self.context.auth_url.replace('v2.0', 'v3') else: # Import auth_token to have keystone_authtoken settings setup. importutils.import_module('keystoneclient.middleware.auth_token') self.v3_endpoint = cfg.CONF.keystone_authtoken.auth_uri.replace( 'v2.0', 'v3') if self.context.trust_id: # Create a client with the specified trust_id, this # populates self.context.auth_token with a trust-scoped token self._client = self._v3_client_init() # The stack domain user ID should be set in heat.conf # It can be created via python-openstackclient # openstack --os-identity-api-version=3 domain create heat # If the domain is specified, then you must specify a domain # admin user. If no domain is specified, we fall back to # legacy behavior with warnings. self._stack_domain_is_id = True self._stack_domain_id = None self.stack_domain = cfg.CONF.stack_user_domain_id if not self.stack_domain and cfg.CONF.stack_user_domain_name: self.stack_domain = cfg.CONF.stack_user_domain_name self._stack_domain_is_id = False self.domain_admin_user = cfg.CONF.stack_domain_admin self.domain_admin_password = cfg.CONF.stack_domain_admin_password if self.stack_domain: if not (self.domain_admin_user and self.domain_admin_password): raise exception.Error(_('heat.conf misconfigured, cannot ' 'specify "stack_user_domain_id" or ' '"stack_user_domain_name" without ' '"stack_domain_admin" and ' '"stack_domain_admin_password"')) else: LOG.warn(_LW('stack_user_domain_id or stack_user_domain_name not ' 'set in heat.conf falling back to using default')) LOG.debug('Using stack domain %s' % self.stack_domain)