def handle_resume(self): """Resume an instance. Note we do not wait for the ACTIVE state, this is polled for by check_resume_complete in a similar way to the create logic so we can take advantage of coroutines. """ if self.resource_id is None: raise exception.Error(_('Cannot resume %s, resource_id not set') % self.name) try: server = self.client().servers.get(self.resource_id) except Exception as e: if self.client_plugin().is_not_found(e): raise exception.NotFound(_('Failed to find instance %s') % self.resource_id) else: raise else: # if the instance has been resumed successful, # no need to resume again if self.client_plugin().get_status(server) != 'ACTIVE': LOG.debug("resuming instance %s" % self.resource_id) server.resume() return server.id
def validate(self): super(Listener, self).validate() protocol = self.properties[self.PROTOCOL] session_sticky = self.properties[self.SESSION_STICKY] sticky_type = self.properties[self.STICKY_SESSION_TYPE] certificate = self.properties[self.CERTIFICATE] tcp_timeout = self.properties[self.TCP_TIMEOUT] if protocol == self.HTTP and session_sticky: if sticky_type != 'insert': msg = (_('Property %(sticky_type)s should be "insert" ' 'when %(protocol)s is %(http)s and ' '%(session_sticky)s is enabled.') % {'sticky_type': self.STICKY_SESSION_TYPE, 'protocol': self.PROTOCOL, 'http': self.HTTP, 'session_sticky': self.SESSION_STICKY}) raise exception.StackValidationFailed(message=msg) if protocol == self.HTTPS: if not certificate: msg = (_('Property %(cert)s is required when %(protocol)s ' 'is %(https)s') % {'cert': self.CERTIFICATE, 'protocol': self.PROTOCOL, 'https': self.HTTPS}) raise exception.StackValidationFailed(message=msg) if tcp_timeout and protocol != self.TCP: msg = (_('Property %(tcpt)s is valid when %(protocol)s ' 'is %(tcp)s') % {'tcpt': self.TCP_TIMEOUT, 'protocol': self.PROTOCOL, 'tcp': self.TCP}) raise exception.StackValidationFailed(message=msg)
def create_plan_by_template(self, req, body): LOG.debug("Create a plan by template") if not self.is_valid_body(body, 'plan'): msg = _("Incorrect request body format.") raise exc.HTTPBadRequest(explanation=msg) context = req.environ['conveyor.context'] tpl_param = body['plan'].get('template') if not tpl_param: msg = _('No template found in body.') raise exc.HTTPBadRequest(explanation=msg) template = self._convert_template_to_json(tpl_param) plan_type = template.get('plan_type') if not plan_type: msg = _("Template must have 'plan_type' field.") raise exc.HTTPBadRequest(explanation=msg) try: plan_name = body['plan'].get('plan_name', None) plan = self._plan_api.create_plan_by_template(context, template, plan_name=plan_name) return {"plan": plan} except Exception as e: LOG.error(unicode(e)) raise exc.HTTPInternalServerError(explanation=unicode(e))
def validate(self): super(RemoteStack, self).validate() try: self.heat() except Exception as ex: exc_info = dict(region=self._region_name, exc=six.text_type(ex)) msg = _('Cannot establish connection to Heat endpoint at region ' '"%(region)s" due to "%(exc)s"') % exc_info raise exception.StackValidationFailed(message=msg) try: params = self.properties[self.PARAMETERS] env = environment.get_child_environment(self.stack.env, params) tmpl = template_format.parse(self.properties[self.TEMPLATE]) args = { 'template': tmpl, 'files': self.stack.t.files, 'environment': env.user_env_as_dict(), } self.heat().stacks.validate(**args) except Exception as ex: exc_info = dict(region=self._region_name, exc=six.text_type(ex)) LOG.error(_LE('exception: %s'), type(ex)) msg = _('Failed validating stack template using Heat endpoint at ' 'region "%(region)s" due to "%(exc)s"') % exc_info raise exception.StackValidationFailed(message=msg)
def parse(env_str): """Takes a string and returns a dict containing the parsed structure.""" if env_str is None: return {} try: env = template_format.yaml.load(env_str, Loader=template_format.yaml_loader) except yaml.YAMLError: # NOTE(prazumovsky): we need to return more informative error for # user, so use SafeLoader, which return error message with template # snippet where error has been occurred. try: env = yaml.load(env_str, Loader=yaml.SafeLoader) except yaml.YAMLError as yea: raise ValueError(yea) else: if env is None: env = {} if not isinstance(env, dict): raise ValueError(_('The environment is not a valid ' 'YAML mapping data type.')) for param in env: if param not in SECTIONS: raise ValueError(_('environment has wrong section "%s"') % param) return env
def clear_table(self, context, stack_id, plan_id, is_heat_stack=False): # need stackname not id stacks = None try: stacks = db_api.plan_stack_get(context, plan_id, read_deleted='yes') except Exception as e: LOG.error(_('Query plan stack for plan (id)s failed: %(err)s'), {'id': plan_id, 'err': e}) raise if stacks: for st in stacks[::-1]: stack_identity = self._make_identity(context.project_id, '', st['stack_id']) # context._session = db_api.get_session() try: self.api.clear_table(context, stack_identity) loop_fun = functools.partial(self._wait_for_table, context, st['stack_id']) timer = loopingcall.FixedIntervalLoopingCall(loop_fun) timer.start(interval=0.5).wait() except exception.EntityNotFound: LOG.warn(_('Delete stack not found in db for plan %s'), plan_id) except Exception as e: LOG.error(_('Clear stack error for plan %(id)s: %(e)s'), {'id': plan_id, 'e': e}) raise self._delete_stack_in_db(context, plan_id, st['stack_id'])
def _exec_replace(self, translation_key, translation_data, value_key, value_data, value): if isinstance(translation_data, list): for item in translation_data: if item.get(self.value_name) and item.get(translation_key): raise ValueError(_('Cannot use %(key)s and ' '%(name)s at the same time.') % dict(key=translation_key, name=self.value_name)) elif item.get(self.value_name) is not None: item[translation_key] = item[self.value_name] del item[self.value_name] elif value is not None: item[translation_key] = value else: if (translation_data and translation_data.get(translation_key) and value_data and value_data.get(value_key)): raise ValueError(_('Cannot use %(key)s and ' '%(name)s at the same time.') % dict(key=translation_key, name=value_key)) translation_data[translation_key] = value # If value defined with value_path, need to delete value_path # property data after it's replacing. if value_data and value_data.get(value_key): del value_data[value_key]
def _get_resource_detail(self, req, id, body): LOG.debug("Get resource detail.") if not self.is_valid_body(body, 'get_resource_detail'): msg = _("Get resource detail request body has not key \ 'get_resource_detail'or the format is incorrect") raise exc.HTTPBadRequest(explanation=msg) params = body['get_resource_detail'] resource_type = params.get('type', None) if not resource_type: msg = _("The body should contain parameter 'type'.") raise exc.HTTPBadRequest(explanation=msg) try: context = req.environ['conveyor.context'] resource = self._resource_api.get_resource_detail(context, resource_type, id) return {"resource": resource} except Exception as e: LOG.error(unicode(e)) raise exc.HTTPInternalServerError(explanation=unicode(e))
def simple_parse(tmpl_str): try: tpl = jsonutils.loads(tmpl_str) except ValueError: try: tpl = yaml.load(tmpl_str, Loader=yaml_loader) except yaml.YAMLError: # NOTE(prazumovsky): we need to return more informative error for # user, so use SafeLoader, which return error message with template # snippet where error has been occurred. try: tpl = yaml.load(tmpl_str, Loader=yaml.SafeLoader) except yaml.YAMLError as yea: yea = six.text_type(yea) msg = _('Error parsing template: %s') % yea raise ValueError(msg) else: if tpl is None: tpl = {} if not isinstance(tpl, dict): raise ValueError(_('The template is not a JSON object ' 'or YAML mapping.')) return tpl
def extract_int(name, value, allow_zero=True, allow_negative=False): if value is None: return None if not strutils.is_int_like(value): raise ValueError(_("Only integer is acceptable by " "'%(name)s'.") % {'name': name}) if value in ('0', 0): if allow_zero: return int(value) raise ValueError(_("Only non-zero integer is acceptable by " "'%(name)s'.") % {'name': name}) try: result = int(value) except (TypeError, ValueError): raise ValueError(_("Value '%(value)s' is invalid for '%(name)s' " "which only accepts integer.") % {'name': name, 'value': value}) if allow_negative is False and result < 0: raise ValueError(_("Value '%(value)s' is invalid for '%(name)s' " "which only accepts non-negative integer.") % {'name': name, 'value': value}) return result
def _validate_create_sources(self): exclusive_options = self._build_exclusive_options() size = self.properties.get(self.SIZE) if size is None and len(exclusive_options) != 1: msg = (_('If neither "%(backup_id)s" nor "%(size)s" is ' 'provided, one and only one of ' '"%(image)s", "%(image_ref)s", "%(source_vol)s", ' '"%(snapshot_id)s" must be specified, but currently ' 'specified options: %(exclusive_options)s.') % {'backup_id': self.BACKUP_ID, 'size': self.SIZE, 'image': self.IMAGE, 'image_ref': self.IMAGE_REF, 'source_vol': self.SOURCE_VOLID, 'snapshot_id': self.SNAPSHOT_ID, 'exclusive_options': exclusive_options}) raise exception.StackValidationFailed(message=msg) elif size and len(exclusive_options) > 1: msg = (_('If "%(size)s" is provided, only one of ' '"%(image)s", "%(image_ref)s", "%(source_vol)s", ' '"%(snapshot_id)s" can be specified, but currently ' 'specified options: %(exclusive_options)s.') % {'size': self.SIZE, 'image': self.IMAGE, 'image_ref': self.IMAGE_REF, 'source_vol': self.SOURCE_VOLID, 'snapshot_id': self.SNAPSHOT_ID, 'exclusive_options': exclusive_options}) raise exception.StackValidationFailed(message=msg)
def validate(self): """Validate provided params.""" res = super(CinderVolume, self).validate() if res is not None: return res # Scheduler hints are only supported from Cinder API v2 if (self.properties[self.CINDER_SCHEDULER_HINTS] and self.client().volume_api_version == 1): raise exception.StackValidationFailed( message=_('Scheduler hints are not supported by the current ' 'volume API.')) # Multi attach is only supported from Cinder API v2 if (self.properties[self.MULTI_ATTACH] and self.client().volume_api_version == 1): raise exception.StackValidationFailed( message=_('Multiple attach is not supported by the current ' 'volume API. Use this property since ' 'Cinder API v2.')) # can not specify both image and imageRef image = self.properties.get(self.IMAGE) imageRef = self.properties.get(self.IMAGE_REF) if image and imageRef: raise exception.ResourcePropertyConflict(self.IMAGE, self.IMAGE_REF) # if not create from backup, need to check other create sources if not self.properties.get(self.BACKUP_ID): self._validate_create_sources()
def limited(items, request, max_limit=CONF.osapi_max_limit): """Return a slice of items according to requested offset and limit. :param items: A sliceable entity :param request: ``wsgi.Request`` possibly containing 'offset' and 'limit' GET variables. 'offset' is where to start in the list, and 'limit' is the maximum number of items to return. If 'limit' is not specified, 0, or > max_limit, we default to max_limit. Negative values for either offset or limit will cause exc.HTTPBadRequest() exceptions to be raised. :kwarg max_limit: The maximum number of items to return from 'items' """ try: offset = int(request.GET.get('offset', 0)) except ValueError: msg = _('offset param must be an integer') raise webob.exc.HTTPBadRequest(explanation=msg) try: limit = int(request.GET.get('limit', max_limit)) except ValueError: msg = _('limit param must be an integer') raise webob.exc.HTTPBadRequest(explanation=msg) if limit < 0: msg = _('limit param must be positive') raise webob.exc.HTTPBadRequest(explanation=msg) if offset < 0: msg = _('offset param must be positive') raise webob.exc.HTTPBadRequest(explanation=msg) limit = min(max_limit, limit or max_limit) range_end = offset + limit return items[offset:range_end]
def _await_instance_status(self, context, instance_id, status): start = time.time() retries = CONF.block_device_allocate_retries if retries < 0: LOG.warn(_LW("Treating negative config value (%(retries)s) for " "'block_device_retries' as 0."), {'retries': retries}) # (1) treat negative config value as 0 # (2) the configured value is 0, one attempt should be made # (3) the configured value is > 0, then the total number attempts # is (retries + 1) attempts = 1 if retries >= 1: attempts = retries + 1 for attempt in range(1, attempts + 1): instance = self.nova_api.get_server(context, instance_id) instance_status = instance.get('status', None) if instance_status == status: LOG.error(_("Instance id: %(id)s finished being %(st)s"), {'id': instance_id, 'st': status}) return attempt greenthread.sleep(CONF.block_device_allocate_retries_interval) if 'SHUTOFF' == status: LOG.error(_("Instance id: %s stop failed"), instance_id) raise exception.InstanceNotStop(instance_id=instance_id, seconds=int(time.time() - start), attempts=attempts) elif 'ACTIVE' == status: LOG.error(_("Instance id: %s start failed"), instance_id) raise exception.InstanceNotStart(instance_id=instance_id, seconds=int(time.time() - start), attempts=attempts) else: raise exception.Error(message="Instance option error.")
def validate(self): super(Subnet, self).validate() subnetpool = self.properties[self.SUBNETPOOL] prefixlen = self.properties[self.PREFIXLEN] cidr = self.properties[self.CIDR] if subnetpool and cidr: raise exception.ResourcePropertyConflict(self.SUBNETPOOL, self.CIDR) if not subnetpool and not cidr: raise exception.PropertyUnspecifiedError(self.SUBNETPOOL, self.CIDR) if prefixlen and cidr: raise exception.ResourcePropertyConflict(self.PREFIXLEN, self.CIDR) ra_mode = self.properties[self.IPV6_RA_MODE] address_mode = self.properties[self.IPV6_ADDRESS_MODE] if (self.properties[self.IP_VERSION] == 4) and ( ra_mode or address_mode): msg = _('ipv6_ra_mode and ipv6_address_mode are not supported ' 'for ipv4.') raise exception.StackValidationFailed(message=msg) if ra_mode and address_mode and (ra_mode != address_mode): msg = _('When both ipv6_ra_mode and ipv6_address_mode are set, ' 'they must be equal.') raise exception.StackValidationFailed(message=msg) gateway_ip = self.properties.get(self.GATEWAY_IP) if (gateway_ip and gateway_ip not in ['~', ''] and not netutils.is_valid_ip(gateway_ip)): msg = (_('Gateway IP address "%(gateway)s" is in ' 'invalid format.'), gateway_ip) raise exception.StackValidationFailed(message=msg)
def _validate_network(self, network): net_id = network.get(self.NETWORK_ID) port = network.get(self.NETWORK_PORT) subnet = network.get(self.NETWORK_SUBNET) fixed_ip = network.get(self.NETWORK_FIXED_IP) if net_id is None and port is None and subnet is None: msg = _('One of the properties "%(id)s", "%(port_id)s" ' 'or "%(subnet)s" should be set for the ' 'specified network of server "%(server)s".' '') % dict(id=self.NETWORK_ID, port_id=self.NETWORK_PORT, subnet=self.NETWORK_SUBNET, server=self.name) raise exception.StackValidationFailed(message=msg) if port and not self.is_using_neutron(): msg = _('Property "%s" is supported only for ' 'Neutron.') % self.NETWORK_PORT raise exception.StackValidationFailed(message=msg) # Nova doesn't allow specify ip and port at the same time if fixed_ip and port: raise exception.ResourcePropertyConflict( "/".join([self.NETWORKS, self.NETWORK_FIXED_IP]), "/".join([self.NETWORKS, self.NETWORK_PORT]))
def check_create_complete(self, data): attributes = self._show_resource() status = attributes['status'] if status == 'PENDING_CREATE': return False elif status == 'ACTIVE': vip_attributes = self.client().show_vip( self.metadata_get()['vip'])['vip'] vip_status = vip_attributes['status'] if vip_status == 'PENDING_CREATE': return False if vip_status == 'ACTIVE': return True if vip_status == 'ERROR': raise exception.ResourceInError( resource_status=vip_status, status_reason=_('error in vip')) raise exception.ResourceUnknownStatus( resource_status=vip_status, result=_('Pool creation failed due to vip')) elif status == 'ERROR': raise exception.ResourceInError( resource_status=status, status_reason=_('error in pool')) else: raise exception.ResourceUnknownStatus( resource_status=status, result=_('Pool creation failed'))
def _translate_section(self, section, sub_section, data, mapping): cfn_objects = {} obj_name = section[:-1] err_msg = _('"%%s" is not a valid keyword inside a %s ' 'definition') % obj_name for name, attrs in sorted(data.items()): cfn_object = {} if not attrs: args = {'object_name': obj_name, 'sub_section': sub_section} message = _('Each %(object_name)s must contain a ' '%(sub_section)s key.') % args raise exception.StackValidationFailed(message=message) try: for attr, attr_value in six.iteritems(attrs): cfn_attr = self._translate(attr, mapping, err_msg) cfn_object[cfn_attr] = attr_value cfn_objects[name] = cfn_object except AttributeError: message = _('"%(section)s" must contain a map of ' '%(obj_name)s maps. Found a [%(_type)s] ' 'instead') % {'section': section, '_type': type(attrs), 'obj_name': obj_name} raise exception.StackValidationFailed(message=message) except KeyError as e: # an invalid keyword was found raise exception.StackValidationFailed(message=e.args[0]) return cfn_objects
def _export_template_and_clone(self, req, id, body): LOG.debug("start export_template_and_clone,the plan id is %s" % id) context = req.environ['conveyor.context'] if not self.is_valid_body(body, 'export_template_and_clone'): LOG.debug("clone request body has not key:clone") raise exc.HTTPUnprocessableEntity() clone_body = body['export_template_and_clone'] destination = clone_body.get('destination') if not isinstance(destination, dict): msg = _("The parameter 'destination' must be a map.") raise exc.HTTPBadRequest(explanation=msg) sys_clone = clone_body.get('sys_clone', False) copy_data = clone_body.get('copy_data', True) resources = clone_body.get('resources') plan = db_api.plan_get(context, id) plan_status = plan['plan_status'] if plan_status not in (p_status.INITIATING, p_status.AVAILABLE, p_status.FINISHED, p_status.CREATING): msg = _("the plan %(plan_id)s in state %(state)s" "can't export_template_and_clone") % { 'plan_id': id, 'state': plan_status, } raise exc.HTTPBadRequest(explanation=msg) self.clone_api.export_template_and_clone(context, id, destination, resources, sys_clone, copy_data)
def signal_software_deployment(self, cnxt, deployment_id, details, updated_at): if not deployment_id: raise ValueError(_('deployment_id must be specified')) sd = software_deployment_object.SoftwareDeployment.get_by_id( cnxt, deployment_id) status = sd.status if not status == rpc_api.SOFTWARE_DEPLOYMENT_IN_PROGRESS: # output values are only expected when in an IN_PROGRESS state return details = details or {} output_status_code = rpc_api.SOFTWARE_DEPLOYMENT_OUTPUT_STATUS_CODE ov = sd.output_values or {} status = None status_reasons = {} status_code = details.get(output_status_code) if status_code and str(status_code) != '0': status = rpc_api.SOFTWARE_DEPLOYMENT_FAILED status_reasons[output_status_code] = _( 'Deployment exited with non-zero status code: %s' ) % details.get(output_status_code) event_reason = 'deployment failed (%s)' % status_code else: event_reason = 'deployment succeeded' for output in sd.config.config['outputs'] or []: out_key = output['name'] if out_key in details: ov[out_key] = details[out_key] if output.get('error_output', False): status = rpc_api.SOFTWARE_DEPLOYMENT_FAILED status_reasons[out_key] = details[out_key] event_reason = 'deployment failed' for out_key in rpc_api.SOFTWARE_DEPLOYMENT_OUTPUTS: ov[out_key] = details.get(out_key) if status == rpc_api.SOFTWARE_DEPLOYMENT_FAILED: # build a status reason out of all of the values of outputs # flagged as error_output status_reasons = [' : '.join((k, six.text_type(status_reasons[k]))) for k in status_reasons] status_reason = ', '.join(status_reasons) else: status = rpc_api.SOFTWARE_DEPLOYMENT_COMPLETE status_reason = _('Outputs received') self.update_software_deployment( cnxt, deployment_id=deployment_id, output_values=ov, status=status, status_reason=status_reason, config_id=None, input_values=None, action=None, updated_at=updated_at) # Return a string describing the outcome of handling the signal data return event_reason
def _check_stack_domain_user(self, user_id, project_id, action): """Sanity check that domain/project is correct.""" user = self.domain_admin_client.users.get(user_id) if user.domain_id != self.stack_domain_id: raise ValueError(_('User %s in invalid domain') % action) if user.default_project_id != project_id: raise ValueError(_('User %s in invalid project') % action)
def _str(self): if self.max is None: fmt = _('The length must be at least %(min)s.') elif self.min is None: fmt = _('The length must be no greater than %(max)s.') else: fmt = _('The length must be in the range %(min)s to %(max)s.') return fmt % self._constraint()
def _check_dict(schema_dict, allowed_keys, entity): if not isinstance(schema_dict, dict): raise exception.InvalidSchemaError( message=_("Invalid %s, expected a mapping") % entity) for key in schema_dict: if key not in allowed_keys: raise exception.InvalidSchemaError( message=_("Invalid key '%(key)s' for %(entity)s") % { "key": key, "entity": entity})
def get_path_component(collection, key): if not isinstance(collection, (collections.Mapping, collections.Sequence)): raise TypeError(_("Can't traverse attribute path")) if not isinstance(key, (six.string_types, int)): raise TypeError(_('Path components in attributes must be strings')) return collection[key]
def from_legacy(cls, schema_dict): """Return a Property Schema object from a legacy schema dictionary.""" # Check for fully-fledged Schema objects if isinstance(schema_dict, cls): return schema_dict unknown = [k for k in schema_dict if k not in SCHEMA_KEYS] if unknown: raise exception.InvalidSchemaError( message=_('Unknown key(s) %s') % unknown) def constraints(): def get_num(key): val = schema_dict.get(key) if val is not None: val = Schema.str_to_num(val) return val if MIN_VALUE in schema_dict or MAX_VALUE in schema_dict: yield constr.Range(get_num(MIN_VALUE), get_num(MAX_VALUE)) if MIN_LENGTH in schema_dict or MAX_LENGTH in schema_dict: yield constr.Length(get_num(MIN_LENGTH), get_num(MAX_LENGTH)) if ALLOWED_VALUES in schema_dict: yield constr.AllowedValues(schema_dict[ALLOWED_VALUES]) if ALLOWED_PATTERN in schema_dict: yield constr.AllowedPattern(schema_dict[ALLOWED_PATTERN]) try: data_type = schema_dict[TYPE] except KeyError: raise exception.InvalidSchemaError( message=_('No %s specified') % TYPE) if SCHEMA in schema_dict: if data_type == Schema.LIST: ss = cls.from_legacy(schema_dict[SCHEMA]) elif data_type == Schema.MAP: schema_dicts = schema_dict[SCHEMA].items() ss = dict((n, cls.from_legacy(sd)) for n, sd in schema_dicts) else: raise exception.InvalidSchemaError( message=_('%(schema)s supplied for %(type)s %(data)s') % dict(schema=SCHEMA, type=TYPE, data=data_type)) else: ss = None return cls(data_type, description=schema_dict.get(DESCRIPTION), default=schema_dict.get(DEFAULT), schema=ss, required=schema_dict.get(REQUIRED, False), constraints=list(constraints()), implemented=schema_dict.get(IMPLEMENTED, True), update_allowed=schema_dict.get(UPDATE_ALLOWED, False), immutable=schema_dict.get(IMMUTABLE, False))
def __init__(self, wait_cond): reasons = wait_cond.get_status_reason(wait_cond.STATUS_SUCCESS) vals = {'len': len(reasons), 'count': wait_cond.properties[wait_cond.COUNT]} if reasons: vals['reasons'] = ';'.join(reasons) message = (_('%(len)d of %(count)d received - %(reasons)s') % vals) else: message = (_('%(len)d of %(count)d received') % vals) super(SwiftSignalTimeout, self).__init__(message)
def __init__(self, wait_condition, handle): reasons = handle.get_status_reason(handle.STATUS_SUCCESS) vals = {'len': len(reasons), 'count': wait_condition.properties[wait_condition.COUNT]} if reasons: vals['reasons'] = ';'.join(reasons) message = (_('%(len)d of %(count)d received - %(reasons)s') % vals) else: message = (_('%(len)d of %(count)d received') % vals) super(WaitConditionTimeout, self).__init__(message)
def create(self): try: ssh = paramiko.SSHClient() if ',' in self.hosts_key_file: files = string.split(self.hosts_key_file, ',') for f in files: ssh.load_host_keys(f) else: ssh.load_host_keys(self.hosts_key_file) # If strict_ssh_host_key_policy is set we want to reject, by # default if there is not entry in the known_hosts file. # Otherwise we use AutoAddPolicy which accepts on the first # Connect but fails if the keys change. load_host_keys can # handle hashed known_host entries. if self.strict_ssh_host_key_policy: ssh.set_missing_host_key_policy(paramiko.RejectPolicy()) else: ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) if self.password: ssh.connect(self.ip, port=self.port, username=self.login, password=self.password, timeout=self.conn_timeout) elif self.privatekey: pkfile = os.path.expanduser(self.privatekey) privatekey = paramiko.RSAKey.from_private_key_file(pkfile) ssh.connect(self.ip, port=self.port, username=self.login, pkey=privatekey, timeout=self.conn_timeout) else: msg = _("Specify a password or private_key") raise exception.CinderException(msg) # Paramiko by default sets the socket timeout to 0.1 seconds, # ignoring what we set through the sshclient. # This doesn't help for # keeping long lived connections. Hence we have to bypass it, by # overriding it after the transport is initialized. We are setting # the sockettimeout to None and setting a # keepalive packet so that, # the server will keep the connection open. All that does is send # a keepalive packet every ssh_conn_timeout seconds. if self.conn_timeout: transport = ssh.get_transport() transport.sock.settimeout(None) transport.set_keepalive(self.conn_timeout) return ssh except Exception as e: msg = _("Error connecting via ssh: %s") % six.text_type(e) LOG.error(msg) raise paramiko.SSHException(msg)
def result(self): strings = function.resolve(self._strings) if not isinstance(self._delim, six.string_types): raise TypeError( _("Delimiter for %s must be string") % self.fn_name) if not isinstance(strings, six.string_types): raise TypeError( _("String to split must be string; got %s") % type(strings)) return strings.split(self._delim)
class VPCGatewayAttachment(resource.Resource): PROPERTIES = ( VPC_ID, INTERNET_GATEWAY_ID, VPN_GATEWAY_ID, ) = ( 'VpcId', 'InternetGatewayId', 'VpnGatewayId', ) properties_schema = { VPC_ID: properties.Schema( properties.Schema.STRING, _('VPC ID for this gateway association.'), required=True ), INTERNET_GATEWAY_ID: properties.Schema( properties.Schema.STRING, _('ID of the InternetGateway.') ), VPN_GATEWAY_ID: properties.Schema( properties.Schema.STRING, _('ID of the VPNGateway to attach to the VPC.'), implemented=False ), } default_client_name = 'neutron' def _vpc_route_tables(self): for res in six.itervalues(self.stack): if (res.has_interface('AWS::EC2::RouteTable') and res.properties.get(route_table.RouteTable.VPC_ID) == self.properties.get(self.VPC_ID)): yield res def add_dependencies(self, deps): super(VPCGatewayAttachment, self).add_dependencies(deps) # Depend on any route table in this template with the same # VpcId as this VpcId. # All route tables must exist before gateway attachment # as attachment happens to routers (not VPCs) for route_tbl in self._vpc_route_tables(): deps += (self, route_tbl) def handle_create(self): client = self.client() external_network_id = InternetGateway.get_external_network_id(client) for router in self._vpc_route_tables(): client.add_gateway_router(router.resource_id, { 'network_id': external_network_id}) def handle_delete(self): for router in self._vpc_route_tables(): with self.client_plugin().ignore_not_found: self.client().remove_gateway_router(router.resource_id)
def _get_property_value(self, key, validate=False): if key not in self: raise KeyError(_('Invalid Property %s') % key) prop = self.props[key] if key in self.data: return self.get_user_value(key, validate) elif prop.has_default(): return prop.get_value(None, validate) elif prop.required(): raise ValueError(_('Property %s not assigned') % key)
def _check_dict(schema_dict, allowed_keys, entity): if not isinstance(schema_dict, dict): raise exception.InvalidSchemaError( message=_("Invalid %s, expected a mapping") % entity) for key in schema_dict: if key not in allowed_keys: raise exception.InvalidSchemaError( message=_("Invalid key '%(key)s' for %(entity)s") % { "key": key, "entity": entity })
def _get_limit_param(request): """Extract integer limit from request or fail.""" try: limit = int(request.GET['limit']) except ValueError: msg = _('limit param must be an integer') raise webob.exc.HTTPBadRequest(explanation=msg) if limit < 0: msg = _('limit param must be positive') raise webob.exc.HTTPBadRequest(explanation=msg) return limit
def validate(self): super(CinderVolumeType, self).validate() if self.properties[self.PROJECTS]: if self.cinder().volume_api_version == 1: raise exception.NotSupported( feature=_('Using Cinder API V1, volume type access')) if self.properties[self.IS_PUBLIC]: msg = (_('Can not specify property "%s" ' 'if the volume type is public.') % self.PROJECTS) raise exception.StackValidationFailed(message=msg)
def validate(self): super(Repeat, self).validate() if not isinstance(self._for_each, function.Function): if not isinstance(self._for_each, collections.Mapping): raise TypeError(_('The "for_each" argument to "%s" must ' 'contain a map') % self.fn_name) if not all(self._valid_list(v) for v in self._for_each.values()): raise TypeError(_('The values of the "for_each" argument ' 'to "%s" must be lists') % self.fn_name)
def adjust(self, adjustment, adjustment_type=sc_util.CFN_CHANGE_IN_CAPACITY, min_adjustment_step=None): """Adjust the size of the scaling group if the cooldown permits.""" if not self._is_scaling_allowed(): LOG.info(_LI("%(name)s NOT performing scaling adjustment, " "cooldown %(cooldown)s"), {'name': self.name, 'cooldown': self.properties[self.COOLDOWN]}) raise exception.NoActionRequired() capacity = grouputils.get_size(self) new_capacity = self._get_new_capacity(capacity, adjustment, adjustment_type, min_adjustment_step) changed_size = new_capacity != capacity # send a notification before, on-error and on-success. notif = { 'stack': self.stack, 'adjustment': adjustment, 'adjustment_type': adjustment_type, 'capacity': capacity, 'groupname': self.FnGetRefId(), 'message': _("Start resizing the group %(group)s") % { 'group': self.FnGetRefId()}, 'suffix': 'start', } notification.send(**notif) try: self.resize(new_capacity) except Exception as resize_ex: with excutils.save_and_reraise_exception(): try: notif.update({'suffix': 'error', 'message': six.text_type(resize_ex), 'capacity': grouputils.get_size(self), }) notification.send(**notif) except Exception: LOG.exception(_LE('Failed sending error notification')) else: notif.update({ 'suffix': 'end', 'capacity': new_capacity, 'message': _("End resizing the group %(group)s") % { 'group': notif['groupname']}, }) notification.send(**notif) finally: self._update_groupwatch() self._finished_scaling("%s : %s" % (adjustment_type, adjustment), changed_size=changed_size) return changed_size
def __init__(self, wait_cond): reasons = wait_cond.get_status_reason(wait_cond.STATUS_SUCCESS) vals = { 'len': len(reasons), 'count': wait_cond.properties[wait_cond.COUNT] } if reasons: vals['reasons'] = ';'.join(reasons) message = (_('%(len)d of %(count)d received - %(reasons)s') % vals) else: message = (_('%(len)d of %(count)d received') % vals) super(SwiftSignalTimeout, self).__init__(message)
def validate(self): """Validate the parameter group. Validate that each parameter belongs to only one Parameter Group and that each parameter name in the group references a valid parameter. """ LOG.debug('Validating Parameter Groups: %s', ', '.join(self.parameter_names)) if self.parameter_groups: if not isinstance(self.parameter_groups, list): raise exception.StackValidationFailed( error=_('Parameter Groups error'), path=[PARAMETER_GROUPS], message=_('The %s should be a list.') % PARAMETER_GROUPS) # Loop through groups and validate parameters grouped_parameters = [] for group in self.parameter_groups: parameters = group.get(PARAMETERS) if parameters is None: raise exception.StackValidationFailed( error=_('Parameter Groups error'), path=[PARAMETER_GROUPS, group.get('label', '')], message=_('The %s must be provided for ' 'each parameter group.') % PARAMETERS) if not isinstance(parameters, list): raise exception.StackValidationFailed( error=_('Parameter Groups error'), path=[PARAMETER_GROUPS, group.get('label', '')], message=_('The %s of parameter group ' 'should be a list.') % PARAMETERS) for param in parameters: # Check if param has been added to a previous group if param in grouped_parameters: raise exception.StackValidationFailed( error=_('Parameter Groups error'), path=[PARAMETER_GROUPS, group.get('label', '')], message=_( 'The %s parameter must be assigned to one ' 'parameter group only.') % param) else: grouped_parameters.append(param) # Check that grouped parameter references a valid Parameter if param not in self.parameter_names: raise exception.StackValidationFailed( error=_('Parameter Groups error'), path=[PARAMETER_GROUPS, group.get('label', '')], message=_( 'The grouped parameter %s does not reference ' 'a valid parameter.') % param)
def __init__(self, min=None, max=None, description=None): if min is max is None: raise exception.InvalidSchemaError( message=_('A length constraint must have a min value and/or ' 'a max value specified.')) super(Length, self).__init__(min, max, description) for param in (min, max): if not isinstance(param, (six.integer_types, type(None))): msg = _('min/max length must be integral') raise exception.InvalidSchemaError(message=msg)
def result(self): args = function.resolve(self.args) if not (isinstance(args, six.string_types)): raise TypeError(_('Argument to "%s" must be a string') % self.fn_name) f = self.files.get(args) if f is None: fmt_data = {'fn_name': self.fn_name, 'file_key': args} raise ValueError(_('No content found in the "files" section for ' '%(fn_name)s path: %(file_key)s') % fmt_data) return f
def result(self): args = function.resolve(self.args) if not args: raise ValueError(_('Function "%s" must have arguments') % self.fn_name) if isinstance(args, six.string_types): param_name = args path_components = [] elif isinstance(args, collections.Sequence): param_name = args[0] path_components = args[1:] else: raise TypeError(_('Argument to "%s" must be string or list') % self.fn_name) if not isinstance(param_name, six.string_types): raise TypeError(_('Parameter name in "%s" must be string') % self.fn_name) try: parameter = self.parameters[param_name] except KeyError: raise exception.UserParameterMissing(key=param_name) def get_path_component(collection, key): if not isinstance(collection, (collections.Mapping, collections.Sequence)): raise TypeError(_('"%s" can\'t traverse path') % self.fn_name) if not isinstance(key, (six.string_types, int)): raise TypeError(_('Path components in "%s" ' 'must be strings') % self.fn_name) if isinstance(collection, collections.Sequence ) and isinstance(key, six.string_types): try: key = int(key) except ValueError: raise TypeError(_("Path components in '%s' " "must be a string that can be " "parsed into an " "integer.") % self.fn_name) return collection[key] try: return six.moves.reduce(get_path_component, path_components, parameter) except (KeyError, IndexError, TypeError): return ''
def __init__(self, min=None, max=None, description=None): super(Range, self).__init__(description) self.min = min self.max = max for param in (min, max): if not isinstance(param, (float, six.integer_types, type(None))): raise exception.InvalidSchemaError( message=_('min/max must be numeric')) if min is max is None: raise exception.InvalidSchemaError( message=_('A range constraint must have a min value and/or ' 'a max value specified.'))
def _build_properties(self, config_id, action): props = { 'config_id': config_id, 'action': action, 'input_values': self.properties.get(self.INPUT_VALUES) } if self._signal_transport_none(): props['status'] = SoftwareDeployment.COMPLETE props['status_reason'] = _('Not waiting for outputs signal') else: props['status'] = SoftwareDeployment.IN_PROGRESS props['status_reason'] = _('Deploy data available') return props
def _parse_args(self): if not self.args: raise ValueError(_('Arguments to "%s" can be of the next ' 'forms: [resource_name] or ' '[resource_name, attribute, (path), ...]' ) % self.fn_name) elif isinstance(self.args, collections.Sequence): if len(self.args) > 1: return super(GetAttAllAttributes, self)._parse_args() else: return self.args[0], None else: raise TypeError(_('Argument to "%s" must be a list') % self.fn_name)
def _parse_args(self): if (not isinstance(self.args, collections.Sequence) or isinstance(self.args, six.string_types)): raise TypeError(_('Argument to "%s" must be a list') % self.fn_name) if len(self.args) < 2: raise ValueError(_('Arguments to "%s" must be of the form ' '[resource_name, attribute, (path), ...]') % self.fn_name) self._path_components = self.args[2:] return tuple(self.args[:2])
def validate(self, with_value=True): try: for key in self.data: if key not in self.props: msg = _("Unknown Property %s") % key raise exception.StackValidationFailed(message=msg) for (key, prop) in self.props.items(): # check that update_allowed and immutable # do not contradict each other if prop.update_allowed() and prop.immutable(): msg = _("Property %(prop)s: %(ua)s and %(im)s " "cannot both be True") % { 'prop': key, 'ua': prop.schema.UPDATE_ALLOWED, 'im': prop.schema.IMMUTABLE } raise exception.InvalidSchemaError(message=msg) if with_value: try: self._get_property_value(key, validate=True) except exception.StackValidationFailed as ex: path = [key] path.extend(ex.path) raise exception.StackValidationFailed( path=path, message=ex.error_message) except ValueError as e: if prop.required() and key not in self.data: path = [] else: path = [key] raise exception.StackValidationFailed( path=path, message=six.text_type(e)) # are there unimplemented Properties if not prop.implemented() and key in self.data: msg = _("Property %s not implemented yet") % key raise exception.StackValidationFailed(message=msg) except exception.StackValidationFailed as ex: # NOTE(prazumovsky): should reraise exception for adding specific # error name and error_prefix to path for correct error message # building. path = self.error_prefix path.extend(ex.path) raise exception.StackValidationFailed(error=ex.error or 'Property error', path=path, message=ex.error_message)
def _user_token(self): project_id = self.stack.stack_user_project_id if not project_id: raise ValueError(_("Can't get user token, user not yet created")) password = getattr(self, 'password', None) # FIXME(shardy): the create and getattr here could allow insane # passwords, e.g a zero length string, if these happen it almost # certainly means a bug elsewhere in heat, so add assertion to catch if password is None: raise ValueError(_("Can't get user token without password")) return self.keystone().stack_domain_user_token( user_id=self._get_user_id(), project_id=project_id, password=password)
def validate(self, validate_value=True, context=None): """Validates the parameter. This method validates if the parameter's schema is valid, and if the default value - if present - or the user-provided value for the parameter comply with the schema. """ err_msg = _("Parameter '%(name)s' is invalid: %(exp)s") try: self.schema.validate(context) if not validate_value: return if self.user_value is not None: self._validate(self.user_value, context) elif self.has_default(): self._validate(self.default(), context) else: raise exception.UserParameterMissing(key=self.name) except exception.StackValidationFailed as ex: msg = err_msg % dict(name=self.name, exp=six.text_type(ex)) raise exception.StackValidationFailed(message=msg) except exception.InvalidSchemaError as ex: msg = err_msg % dict(name=self.name, exp=six.text_type(ex)) raise exception.InvalidSchemaError(message=msg)
def _err_msg(self, value): constraint = self.custom_constraint if constraint is None: return _('"%(value)s" does not validate %(name)s ' '(constraint not found)') % { "value": value, "name": self.name } error = getattr(constraint, "error", None) if error: return error(value) return _('"%(value)s" does not validate %(name)s') % { "value": value, "name": self.name }
def __init__(self, pattern, description=None): super(AllowedPattern, self).__init__(description) if not isinstance(pattern, six.string_types): raise exception.InvalidSchemaError( message=_('AllowedPattern must be a string')) self.pattern = pattern self.match = re.compile(pattern).match
def __init__(self, allowed, description=None): super(AllowedValues, self).__init__(description) if (not isinstance(allowed, collections.Sequence) or isinstance(allowed, six.string_types)): raise exception.InvalidSchemaError( message=_('AllowedValues must be a list')) self.allowed = tuple(allowed)
def __call__(self, environ, start_response): r"""Subclasses will probably want to implement __call__ like this: @webob.dec.wsgify(RequestClass=Request) def __call__(self, req): # Any of the following objects work as responses: # Option 1: simple string res = 'message\n' # Option 2: a nicely formatted HTTP exception page res = exc.HTTPForbidden(explanation='Nice try') # Option 3: a webob Response object (in case you need to play with # headers, or you want to be treated like an iterable) res = Response(); res.app_iter = open('somefile') # Option 4: any wsgi app to be run next res = self.application # Option 5: you can get a Response object for a wsgi app, too, to # play with headers etc res = req.get_response(self.application) # You can then just return your response... return res # ... or set req.response and return None. req.response = res See the end of http://pythonpaste.org/webob/modules/dec.html for more info. """ raise NotImplementedError(_('You must implement __call__'))
def check_delete_server_complete(self, server_id): """Wait for server to disappear from Nova.""" try: server = self.fetch_server(server_id) except Exception as exc: self.ignore_not_found(exc) return True if not server: return False task_state_in_nova = getattr(server, 'OS-EXT-STS:task_state', None) # the status of server won't change until the delete task has done if task_state_in_nova == 'deleting': return False status = self.get_status(server) if status in ("DELETED", "SOFT_DELETED"): return True if status == 'ERROR': fault = getattr(server, 'fault', {}) message = fault.get('message', 'Unknown') code = fault.get('code') errmsg = _("Server %(name)s delete failed: (%(code)s) " "%(message)s") % dict( name=server.name, code=code, message=message) raise exception.ResourceInError(resource_status=status, status_reason=errmsg) return False
def _create_shadow_tables(migrate_engine): meta = MetaData(migrate_engine) meta.reflect(migrate_engine) table_names = meta.tables.keys() meta.bind = migrate_engine for table_name in table_names: table = Table(table_name, meta, autoload=True) columns = [] for column in table.columns: column_copy = None # NOTE(boris-42): BigInteger is not supported by sqlite, so # after copy it will have NullType, other # types that are used in Nova are supported by # sqlite. if isinstance(column.type, NullType): column_copy = Column(column.name, BigInteger(), default=0) column_copy = column.copy() columns.append(column_copy) shadow_table_name = 'shadow_' + table_name shadow_table = Table(shadow_table_name, meta, *columns, mysql_engine='InnoDB') try: shadow_table.create(checkfirst=True) except Exception: LOG.info(repr(shadow_table)) LOG.exception(_('Exception while creating table.')) raise
def _db_error(caught_exception): print(caught_exception) print( _("The above error may show that the database has not " "been created.\nPlease create a database using " "'fs_gateway-manage db sync' before running this command.")) exit(1)
def _update_timeout(self, batch_cnt, pause_sec): total_pause_time = pause_sec * max(batch_cnt - 1, 0) if total_pause_time >= self.stack.timeout_secs(): msg = _('The current %s will result in stack update ' 'timeout.') % rsrc_defn.UPDATE_POLICY raise ValueError(msg) return self.stack.timeout_secs() - total_pause_time
def from_arn(cls, arn): """Generate a new HeatIdentifier by parsing the supplied ARN.""" fields = arn.split(':') if len(fields) < 6 or fields[0].lower() != 'arn': raise ValueError(_('"%s" is not a valid ARN') % arn) id_fragment = ':'.join(fields[5:]) path = cls.path_re.match(id_fragment) if fields[1] != 'openstack' or fields[2] != 'heat' or not path: raise ValueError(_('"%s" is not a valid Heat ARN') % arn) return cls(urlparse.unquote(fields[4]), urlparse.unquote(path.group(1)), urlparse.unquote(path.group(2)), urlparse.unquote(path.group(3)))
def template_data(self): # we want to have the latest possible template. # 1. look in files # 2. try download # 3. look in the db reported_excp = None t_data = self.stack.t.files.get(self.template_name) stored_t_data = t_data if not t_data and self.template_name.endswith((".yaml", ".template")): try: t_data = self.get_template_file(self.template_name, self.allowed_schemes) except exception.NotFound as err: if self.action == self.UPDATE: raise reported_excp = err if t_data is None: if self.nested() is not None: t_data = jsonutils.dumps(self.nested().t.t) if t_data is not None: if t_data != stored_t_data: self.stack.t.files[self.template_name] = t_data self.stack.t.env.register_class(self.resource_type, self.template_name, path=self.resource_path) return t_data if reported_excp is None: reported_excp = ValueError( _('Unknown error retrieving %s') % self.template_name) raise reported_excp