def validate_instances_list_for_transfer(instances): if not instances: raise exception.InvalidInput( "No instance identifiers provided for transfer action.") if not isinstance(instances, list): raise exception.InvalidInput( "Instances must be a list. Got type %s: %s" % (type(instances), instances)) appearances = {} for instance in instances: if instance in appearances: appearances[instance] = appearances[instance] + 1 else: appearances[instance] = 1 duplicates = { inst: count for (inst, count) in appearances.items() if count > 1 } if duplicates: raise exception.InvalidInput( "Transfer action instances (%s) list contained duplicates: %s " % (instances, duplicates)) return instances
def validate_user_scripts(user_scripts): if user_scripts is None: user_scripts = {} if not isinstance(user_scripts, dict): raise exception.InvalidInput( reason='"user_scripts" must be of JSON object format') global_scripts = user_scripts.get('global', {}) if not isinstance(global_scripts, dict): raise exception.InvalidInput( reason='"global" must be a mapping between the identifiers of the ' 'supported OS types and their respective scripts.') for os_type in global_scripts.keys(): if os_type not in constants.VALID_OS_TYPES: raise exception.InvalidInput( reason='The provided global user script os_type "%s" is ' 'invalid. Must be one of the ' 'following: %s' % (os_type, constants.VALID_OS_TYPES)) instance_scripts = user_scripts.get('instances', {}) if not isinstance(instance_scripts, dict): raise exception.InvalidInput( reason='"instances" must be a mapping between the identifiers of ' 'the instances in the Replica/Migration and their ' 'respective scripts.') return user_scripts
def _update_sqlalchemy_object_fields(obj, updateable_fields, values_to_update): """ Updates the given 'values_to_update' on the provided sqlalchemy object as long as they are included as 'updateable_fields'. :param obj: object: sqlalchemy object :param updateable_fields: list(str): list of fields which are updateable :param values_to_update: dict: dict with the key/vals to update """ if not isinstance(values_to_update, dict): raise exception.InvalidInput( "Properties to update for DB object of type '%s' must be a dict, " "got the following (type %s): %s" % ( type(obj), type(values_to_update), values_to_update)) non_updateable_fields = set( values_to_update.keys()).difference( set(updateable_fields)) if non_updateable_fields: raise exception.Conflict( "Fields %s for '%s' database cannot be updated. " "Only updateable fields are: %s" % ( non_updateable_fields, type(obj), updateable_fields)) for field_name, field_val in values_to_update.items(): if not hasattr(obj, field_name): raise exception.InvalidInput( "No region field named '%s' to update." % field_name) setattr(obj, field_name, field_val) LOG.debug( "Successfully updated the following fields on DB object " "of type '%s': %s" % (type(obj), values_to_update.keys()))
def _check_string_length(value, name, min_length=0, max_length=None): """Check the length of specified string. :param value: the value of the string :param name: the name of the string :param min_length: the min_length of the string :param max_length: the max_length of the string """ if not isinstance(value, six.string_types): msg = _("%s is not a string or unicode") % name raise exception.InvalidInput(message=msg) if len(value) < min_length: msg = _("%(name)s has a minimum character requirement of " "%(min_length)s.") % { 'name': name, 'min_length': min_length } raise exception.InvalidInput(message=msg) if max_length and len(value) > max_length: msg = _("%(name)s has more than %(max_length)s " "characters.") % { 'name': name, 'max_length': max_length } raise exception.InvalidInput(message=msg)
def _wrapper(*args, **kwargs): try: return func(*args, **kwargs) except KeyError as err: LOG.exception(err) if err.args: key = err.args[0] exc_message = _build_keyerror_message( resource, method, key) else: exc_message = str(err) raise exception.InvalidInput(exc_message) except Exception as err: LOG.exception(err) msg = getattr(err, "msg", str(err)) raise exception.InvalidInput(reason=msg)
def get_endpoint_destination_minion_pool_options(self, ctxt, platform_name, connection_info, env, option_names): provider = providers_factory.get_provider( platform_name, constants.PROVIDER_TYPE_DESTINATION_MINION_POOL, None, raise_if_not_found=False) if not provider: raise exception.InvalidInput( "Provider plugin for platform '%s' does not support " "destination minion pool creation or management." % (platform_name)) secret_connection_info = utils.get_secret_connection_info( ctxt, connection_info) options = provider.get_minion_pool_options(ctxt, secret_connection_info, env=env, option_names=option_names) # NOTE: the structure of option values is the same for minion pools: schemas.validate_value( options, schemas.CORIOLIS_DESTINATION_ENVIRONMENT_OPTIONS_SCHEMA) return options
def _validate_update_body(self, id, context, body): replica = self._replica_api.get_replica(context, id) try: merged_body = self._get_merged_replica_values( replica, body['replica']) origin_endpoint_id = replica["origin_endpoint_id"] destination_endpoint_id = replica["destination_endpoint_id"] self._endpoints_api.validate_source_environment( context, origin_endpoint_id, merged_body["source_environment"]) destination_environment = merged_body["destination_environment"] self._endpoints_api.validate_target_environment( context, destination_endpoint_id, destination_environment) api_utils.validate_network_map(merged_body["network_map"]) api_utils.validate_storage_mappings( merged_body["storage_mappings"]) return merged_body except Exception as ex: LOG.exception(ex) raise exception.InvalidInput(getattr(ex, "message", str(ex)))
def _get_vm(self, si, instance_path): vm = None container = si.content.rootFolder path_items = [ p.replace('\\/', '/') for p in re.split(r'(?<!\\)/', instance_path) ] if len(path_items) == 1: if len(container.childEntity) > 1: raise exception.InvalidInput( "There's more than one container in the VMWare root " "folder, please specify the full path for the VM, e.g. " "\"Datacenter1/VM1\"") else: container = container.childEntity[0].vmFolder LOG.debug("VM path items:", path_items) for i, path_item in enumerate(path_items): l = [o for o in container.childEntity if o.name == path_item] if not l: raise exception.InstanceNotFound(instance_name=instance_path) item = l[0] if (i + 1 == len(path_items) and isinstance(item, vim.VirtualMachine)): vm = item elif isinstance(item, vim.Datacenter): container = item.vmFolder else: container = item if vm is None: raise exception.InstanceNotFound(instance_name=instance_path) return vm
def decode_base64_param(value, is_json=False): try: decoded = base64.b64decode(value).decode() if is_json: decoded = json.loads(decoded) return decoded except (binascii.Error, TypeError, json.decoder.JSONDecodeError) as ex: raise exception.InvalidInput(reason=str(ex))
def _validate_create_body(self, ctxt, body): try: minion_pool = body["minion_pool"] name = minion_pool["pool_name"] endpoint_id = minion_pool["endpoint_id"] pool_os_type = minion_pool["pool_os_type"] if pool_os_type not in constants.VALID_OS_TYPES: raise Exception( "The provided pool OS type '%s' is invalid. Must be one " "of the following: %s" % ( pool_os_type, constants.VALID_OS_TYPES)) pool_platform = minion_pool["pool_platform"] supported_pool_platforms = [ constants.PROVIDER_PLATFORM_SOURCE, constants.PROVIDER_PLATFORM_DESTINATION] if pool_platform not in supported_pool_platforms: raise Exception( "The provided pool platform ('%s') is invalid. Must be one" " of the following: %s" % ( pool_platform, supported_pool_platforms)) if pool_platform == constants.PROVIDER_PLATFORM_SOURCE and ( pool_os_type != constants.OS_TYPE_LINUX): raise Exception( "Source Minion Pools are required to be of OS type " "'%s', not '%s'." % ( constants.OS_TYPE_LINUX, pool_os_type)) environment_options = minion_pool["environment_options"] if pool_platform == constants.PROVIDER_PLATFORM_SOURCE: self._endpoints_api.validate_endpoint_source_minion_pool_options( ctxt, endpoint_id, environment_options) elif pool_platform == constants.PROVIDER_PLATFORM_DESTINATION: self._endpoints_api.validate_endpoint_destination_minion_pool_options( ctxt, endpoint_id, environment_options) minimum_minions = minion_pool.get("minimum_minions", 1) maximum_minions = minion_pool.get( "maximum_minions", minimum_minions) minion_max_idle_time = minion_pool.get( "minion_max_idle_time", 1) self._check_pool_numeric_values( minimum_minions, maximum_minions, minion_max_idle_time) minion_retention_strategy = minion_pool.get( "minion_retention_strategy", constants.MINION_POOL_MACHINE_RETENTION_STRATEGY_DELETE) self._check_pool_retention_strategy( minion_retention_strategy) notes = minion_pool.get("notes") return ( name, endpoint_id, pool_platform, pool_os_type, environment_options, minimum_minions, maximum_minions, minion_max_idle_time, minion_retention_strategy, notes) except Exception as ex: LOG.exception(ex) if hasattr(ex, "message"): msg = ex.message else: msg = str(ex) raise exception.InvalidInput(msg)
def _validate_update_body(self, id, context, body): try: minion_pool = body["minion_pool"] if 'endpoint_id' in minion_pool: raise Exception( "The 'endpoint_id' of a minion pool cannot be updated.") if 'pool_platform' in minion_pool: raise Exception( "The 'pool_platform' of a minion pool cannot be updated.") vals = {k: minion_pool[k] for k in minion_pool.keys() & {"name", "environment_options", "minimum_minions", "maximum_minions", "minion_max_idle_time", "minion_retention_strategy", "notes", "pool_os_type"}} if 'minion_retention_strategy' in vals: self._check_pool_retention_strategy( vals['minion_retention_strategy']) if any([ f in vals for f in [ 'environment_options', 'minimum_minions', 'maximum_minions', 'minion_max_idle_time']]): minion_pool = self._minion_pool_api.get_minion_pool( context, id) self._check_pool_numeric_values( vals.get( 'minimum_minions', minion_pool['minimum_minions']), vals.get( 'maximum_minions', minion_pool['maximum_minions']), vals.get('minion_max_idle_time')) if 'environment_options' in vals: if minion_pool['pool_platform'] == ( constants.PROVIDER_PLATFORM_SOURCE): self._endpoints_api.validate_endpoint_source_minion_pool_options( # TODO(aznashwan): remove endpoint ID fields redundancy # once DB models are overhauled: context, minion_pool['origin_endpoint_id'], vals['environment_options']) elif minion_pool['pool_platform'] == ( constants.PROVIDER_PLATFORM_DESTINATION): self._endpoints_api.validate_endpoint_destination_minion_pool_options( # TODO(aznashwan): remove endpoint ID fields redundancy # once DB models are overhauled: context, minion_pool['origin_endpoint_id'], vals['environment_options']) else: raise Exception( "Unknown pool platform: %s" % minion_pool[ 'pool_platform']) return vals except Exception as ex: LOG.exception(ex) if hasattr(ex, "message"): msg = ex.message else: msg = str(ex) raise exception.InvalidInput(msg)
def _validate_expiration_date(self, expiration_date): if expiration_date is None: return expiration_date exp = timeutils.normalize_time( timeutils.parse_isotime(expiration_date)) now = timeutils.utcnow() if now > exp: raise exception.InvalidInput( "expiration_date is in the past") return exp
def add_endpoint_region_mapping(context, endpoint_region_mapping): region_id = endpoint_region_mapping.region_id endpoint_id = endpoint_region_mapping.endpoint_id if None in [region_id, endpoint_id]: raise exception.InvalidInput( "Provided endpoint region mapping params for the region ID " "('%s') and the endpoint ID ('%s') must both be non-null." % ( region_id, endpoint_id)) _session(context).add(endpoint_region_mapping)
def add_service_region_mapping(context, service_region_mapping): region_id = service_region_mapping.region_id service_id = service_region_mapping.service_id if None in [region_id, service_id]: raise exception.InvalidInput( "Provided service region mapping params for the region ID " "('%s') and the service ID ('%s') must both be non-null." % ( region_id, service_id)) _session(context).add(service_region_mapping)
def create(self, req, replica_id, body): LOG.debug("Got request: %r %r %r" % (req, replica_id, body)) try: schedule, enabled, exp_date, shutdown = self._validate_create_body( body) except Exception as err: raise exception.InvalidInput(err) return replica_schedule_view.single(req, self._schedule_api.create( req.environ['coriolis.context'], replica_id, schedule, enabled, exp_date, shutdown))
def _validate_update_body(self, body): try: endpoint = body["endpoint"] return {k: endpoint[k] for k in endpoint.keys() & {"name", "description", "connection_info"}} except Exception as ex: LOG.exception(ex) if hasattr(ex, "message"): msg = ex.message else: msg = str(ex) raise exception.InvalidInput(msg)
def update_region(context, region_id, updated_values): if not region_id: raise exception.InvalidInput( "No region ID specified for updating.") region = get_region(context, region_id) if not region: raise exception.NotFound( "Region with ID '%s' does not exist." % region_id) updateable_fields = ["name", "description", "enabled"] _update_sqlalchemy_object_fields( region, updateable_fields, updated_values)
def update(self, req, replica_id, id, body): LOG.debug("Got request: %r %r %r %r" % ( req, replica_id, id, body)) try: update_values = self._validate_update_body(body) except Exception as err: raise exception.InvalidInput(err) return replica_schedule_view.single(req, self._schedule_api.update( req.environ['coriolis.context'], replica_id, id, update_values))
def _validate_migration_input(self, context, migration): try: origin_endpoint_id = migration["origin_endpoint_id"] destination_endpoint_id = migration["destination_endpoint_id"] origin_minion_pool_id = migration.get('origin_minion_pool_id') destination_minion_pool_id = migration.get( 'destination_minion_pool_id') instance_osmorphing_minion_pool_mappings = migration.get( 'instance_osmorphing_minion_pool_mappings', {}) destination_environment = migration.get("destination_environment", {}) instances = migration["instances"] notes = migration.get("notes") skip_os_morphing = migration.get("skip_os_morphing", False) shutdown_instances = migration.get("shutdown_instances", False) replication_count = int(migration.get("replication_count", 2)) if replication_count not in range(1, 11): raise ValueError( "'replication_count' must be an integer between 1 and 10." " Got: %s" % replication_count) source_environment = migration.get("source_environment", {}) self._endpoints_api.validate_source_environment( context, origin_endpoint_id, source_environment) network_map = migration.get("network_map", {}) api_utils.validate_network_map(network_map) destination_environment['network_map'] = network_map # NOTE(aznashwan): we validate the destination environment for the # import provider before appending the 'storage_mappings' parameter # for plugins with strict property name checks which do not yet # support storage mapping features: self._endpoints_api.validate_target_environment( context, destination_endpoint_id, destination_environment) # TODO(aznashwan): until the provider plugin interface is updated # to have separate 'network_map' and 'storage_mappings' fields, # we add them as part of the destination environment: storage_mappings = migration.get("storage_mappings", {}) api_utils.validate_storage_mappings(storage_mappings) destination_environment['storage_mappings'] = storage_mappings return (origin_endpoint_id, destination_endpoint_id, origin_minion_pool_id, destination_minion_pool_id, instance_osmorphing_minion_pool_mappings, source_environment, destination_environment, instances, notes, skip_os_morphing, replication_count, shutdown_instances, network_map, storage_mappings) except Exception as ex: LOG.exception(ex) msg = getattr(ex, "message", str(ex)) raise exception.InvalidInput(msg)
def _validate_update_body(self, body): try: service = body["service"] return { k: service[k] for k in service.keys() & {"enabled", "mapped_regions"} } except Exception as ex: LOG.exception(ex) if hasattr(ex, "message"): msg = ex.message else: msg = str(ex) raise exception.InvalidInput(msg)
def create(self, req, replica_id, body): context = req.environ["coriolis.context"] context.can( schedules_policies.get_replica_schedules_policy_label("create")) LOG.debug("Got request: %r %r %r" % (req, replica_id, body)) try: schedule, enabled, exp_date, shutdown = self._validate_create_body( body) except Exception as err: raise exception.InvalidInput(err) return replica_schedule_view.single(req, self._schedule_api.create( context, replica_id, schedule, enabled, exp_date, shutdown))
def _validate_update_body(self, body): try: region = body["region"] return { k: region[k] for k in region.keys() & {"name", "description", "enabled"} } except Exception as ex: LOG.exception(ex) if hasattr(ex, "message"): msg = ex.message else: msg = str(ex) raise exception.InvalidInput(msg)
def update_minion_machine(context, minion_machine_id, updated_values): if not minion_machine_id: raise exception.InvalidInput( "No minion_machine ID specified for updating.") minion_machine = get_minion_machine(context, minion_machine_id) if not minion_machine: raise exception.NotFound( "MinionMachine with ID '%s' does not exist." % minion_machine_id) updateable_fields = [ "connection_info", "provider_properties", "status", "backup_writer_connection_info", "allocated_action"] _update_sqlalchemy_object_fields( minion_machine, updateable_fields, updated_values)
def _validate_create_body(self, body): try: region = body["region"] name = region["name"] description = region.get("description", "") enabled = region.get("enabled", True) return name, description, enabled except Exception as ex: LOG.exception(ex) if hasattr(ex, "message"): msg = ex.message else: msg = str(ex) raise exception.InvalidInput(msg)
def _validate_create_body(self, body): try: endpoint = body["endpoint"] name = endpoint["name"] description = endpoint.get("description") endpoint_type = endpoint["type"] connection_info = endpoint["connection_info"] return name, endpoint_type, description, connection_info except Exception as ex: LOG.exception(ex) if hasattr(ex, "message"): msg = ex.message else: msg = str(ex) raise exception.InvalidInput(msg)
def update(self, req, replica_id, id, body): context = req.environ["coriolis.context"] context.can( schedules_policies.get_replica_schedules_policy_label("update")) LOG.debug("Got request: %r %r %r %r" % ( req, replica_id, id, body)) try: update_values = self._validate_update_body(body) except Exception as err: raise exception.InvalidInput(err) return replica_schedule_view.single(req, self._schedule_api.update( context, replica_id, id, update_values))
def _validate_create_body(self, body): schedule = body.get("schedule") if schedule is None: raise exception.InvalidInput( "schedule is required") schedule = self._validate_schedule(schedule) schemas.validate_value( body, schemas.SCHEDULE_API_BODY_SCHEMA, format_checker=jsonschema.FormatChecker()) enabled = body.get("enabled", True) exp = body.get("expiration_date", None) if exp is not None: exp = self._validate_expiration_date(exp) shutdown = body.get("shutdown_instance", False) return (schedule, enabled, exp, shutdown)
def _validate_create_body(self, body): try: service = body["service"] host = service["host"] binary = service["binary"] topic = service["topic"] mapped_regions = service.get('mapped_regions', []) enabled = service.get("enabled", True) return host, binary, topic, mapped_regions, enabled except Exception as ex: LOG.exception(ex) if hasattr(ex, "message"): msg = ex.message else: msg = str(ex) raise exception.InvalidInput(msg)
def _validate_create_body(self, body): try: replica = body["replica"] origin_endpoint_id = replica["origin_endpoint_id"] destination_endpoint_id = replica["destination_endpoint_id"] destination_environment = replica.get("destination_environment") instances = replica["instances"] notes = replica.get("notes") return (origin_endpoint_id, destination_endpoint_id, destination_environment, instances, notes) except Exception as ex: LOG.exception(ex) if hasattr(ex, "message"): msg = ex.message else: msg = str(ex) raise exception.InvalidInput(msg)
def _validate_migration_input(self, migration): try: origin_endpoint_id = migration["origin_endpoint_id"] destination_endpoint_id = migration["destination_endpoint_id"] destination_environment = migration.get("destination_environment") instances = migration["instances"] notes = migration.get("notes") skip_os_morphing = migration.get("skip_os_morphing", False) return (origin_endpoint_id, destination_endpoint_id, destination_environment, instances, notes, skip_os_morphing) except Exception as ex: LOG.exception(ex) if hasattr(ex, "message"): msg = ex.message else: msg = str(ex) raise exception.InvalidInput(msg)