Пример #1
0
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
Пример #2
0
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
Пример #3
0
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()))
Пример #4
0
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)
Пример #5
0
 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)
Пример #6
0
    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
Пример #7
0
    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)))
Пример #8
0
    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
Пример #9
0
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))
Пример #10
0
    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)
Пример #11
0
    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)
Пример #12
0
 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
Пример #13
0
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)
Пример #14
0
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)
Пример #15
0
    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))
Пример #16
0
 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)
Пример #17
0
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)
Пример #18
0
    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))
Пример #19
0
    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)
Пример #20
0
 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)
Пример #21
0
    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))
Пример #22
0
 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)
Пример #23
0
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)
Пример #24
0
 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)
Пример #25
0
 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)
Пример #26
0
    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))
Пример #27
0
    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)
Пример #28
0
 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)
Пример #29
0
    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)
Пример #30
0
    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)