Ejemplo n.º 1
0
def _verify_weekdays(weekdays, recurrence):
    if not weekdays:
        return
    if not isinstance(weekdays, list):
        raise manager_exceptions.BadParametersError(
            "weekdays: expected a list, but got: {}".format(weekdays))
    weekdays_caps = [d.upper() for d in weekdays]
    valid_weekdays = {str(d) for d in rrule.weekdays}

    complex_weekdays_freq = False
    if recurrence:
        _, recurrence = parse_recurrence(recurrence)
        complex_weekdays_freq = (recurrence in ['mo', 'month', 'y', 'year'])

    for weekday in weekdays_caps:
        parsed = re.findall(r"^([1-4]|L-)?({})".format(
            '|'.join(valid_weekdays)), weekday)
        if not parsed:
            raise manager_exceptions.BadParametersError(
                "weekdays list contains an invalid weekday `{}`. Valid "
                "weekdays are: {} or their lowercase values, optionally "
                "prefixed by 1-4 or l-/L-.".format(weekday,
                                                   '|'.join(valid_weekdays)))
        if parsed[0][0] and not complex_weekdays_freq:
            raise manager_exceptions.BadParametersError(
                "complex weekday expression {} can only be used with a months|"
                "years recurrence, but got {}.".format(weekday, recurrence))
    return weekdays_caps
Ejemplo n.º 2
0
    def get(self, pagination=None, all_tenants=None, filters=None):
        target_field = request.args.get('_target_field')
        subfield = request.args.get('_sub_field')

        get_all_results = rest_utils.verify_and_convert_bool(
            '_get_all_results', request.args.get('_get_all_results', False))

        if target_field not in self.summary_fields:
            raise manager_exceptions.BadParametersError(
                'Field {target} is not available for summary. Valid fields '
                'are: {valid}'.format(
                    target=target_field,
                    valid=', '.join(self.summary_fields),
                ))

        if subfield and subfield not in self.summary_fields:
            raise manager_exceptions.BadParametersError(
                'Field {target} is not available for summary. Valid fields '
                'are: {valid}'.format(
                    target=subfield,
                    valid=', '.join(self.summary_fields),
                ))

        return get_storage_manager().summarize(
            target_field=target_field,
            sub_field=subfield,
            model_class=self.model,
            pagination=pagination,
            all_tenants=all_tenants,
            get_all_results=get_all_results,
            filters=filters,
        )
Ejemplo n.º 3
0
def parse_datetime(datetime_str):
    """
    :param datetime_str: A string representing date and time with timezone
                         information.
    :return: A datetime object, converted to UTC, with no timezone info.
    """
    # Parse the string to datetime object
    date_with_offset = dateutil.parser.parse(datetime_str)
    # Convert the date to UTC
    try:
        utc_date = date_with_offset.astimezone(pytz.utc)
    except ValueError:
        raise manager_exceptions.BadParametersError(
            'Date `{0}` missing timezone information, please provide'
            ' valid date. \nExpected format: YYYYMMDDHHMM+HHMM or'
            ' YYYYMMDDHHMM-HHMM i.e: 201801012230-0500'
            ' (Jan-01-18 10:30pm EST)'.format(datetime_str))
    # Date is in UTC, tzinfo is not necessary
    utc_date = utc_date.replace(tzinfo=None)
    now = datetime.utcnow()
    if utc_date <= now:
        raise manager_exceptions.BadParametersError(
            'Date `{0}` has already passed, please provide'
            ' valid date. \nExpected format: YYYYMMDDHHMM+HHMM or'
            ' YYYYMMDDHHMM-HHMM i.e: 201801012230-0500'
            ' (Jan-01-18 10:30pm EST)'.format(datetime_str))

    return utc_date
Ejemplo n.º 4
0
def validate_inputs(input_dict):
    for input_name, input_value in input_dict.iteritems():
        prefix = 'The `{0}` argument'.format(input_name)

        if not input_value:
            raise manager_exceptions.BadParametersError(
                '{0} is empty'.format(prefix)
            )

        if len(input_value) > 256:
            raise manager_exceptions.BadParametersError(
                '{0} is too long. Maximum allowed length is 256 '
                'characters'.format(prefix)
            )

        # urllib.quote changes all chars except alphanumeric chars and _-.
        quoted_value = urllib.quote(input_value, safe='')
        if quoted_value != input_value:
            raise manager_exceptions.BadParametersError(
                '{0} contains illegal characters. Only letters, digits and the'
                ' characters "-", "." and "_" are allowed'.format(prefix)
            )

        if input_value[0] not in ascii_letters:
            raise manager_exceptions.BadParametersError(
                '{0} must begin with a letter'.format(prefix)
            )
Ejemplo n.º 5
0
    def _save_file_locally(self, archive_target_path):
        url_key = self._get_data_url_key()
        if url_key in request.args:
            if request.data or 'Transfer-Encoding' in request.headers:
                raise manager_exceptions.BadParametersError(
                    "Can't pass both a {0} URL via query parameters "
                    "and {0} data via the request body at the same time".
                    format(self._get_kind()))
            data_url = request.args[url_key]
            try:
                with contextlib.closing(urlopen(data_url)) as urlf:
                    with open(archive_target_path, 'w') as f:
                        f.write(urlf.read())
            except URLError:
                raise manager_exceptions.ParamUrlNotFoundError(
                    "URL {0} not found - can't download {1} archive".format(
                        data_url, self._get_kind()))
            except ValueError:
                raise manager_exceptions.BadParametersError(
                    "URL {0} is malformed - can't download {1} archive".format(
                        data_url, self._get_kind()))

        elif 'Transfer-Encoding' in request.headers:
            with open(archive_target_path, 'w') as f:
                for buffered_chunked in chunked.decode(request.input_stream):
                    f.write(buffered_chunked)
        else:
            if not request.data:
                raise manager_exceptions.BadParametersError(
                    'Missing {0} archive in request body or '
                    '"{1}" in query parameters'.format(self._get_kind(),
                                                       url_key))
            uploaded_file_data = request.data
            with open(archive_target_path, 'w') as f:
                f.write(uploaded_file_data)
Ejemplo n.º 6
0
def verify_role(role_name, is_system_role=False):
    """Make sure that role name is present in the system.

    :param role_name: Role name to validate against database content.
    :param is_system_role: True if system_role, False if tenant_role
    :raises: BadParametersError when role is not found in the system or is
    not from the right type

    """
    expected_role_type = 'system_role' if is_system_role else 'tenant_role'

    # Get role by name
    role = next((r for r in config.instance.authorization_roles
                 if r['name'] == role_name), None)

    # Role not found
    if role is None:
        valid_roles = [
            r['name'] for r in config.instance.authorization_roles
            if r['type'] in (expected_role_type, 'any')
        ]
        raise manager_exceptions.BadParametersError(
            'Invalid role: `{0}`. Valid {1} roles are: {2}'.format(
                role_name, expected_role_type, valid_roles))

    # Role type doesn't match
    if role['type'] not in (expected_role_type, 'any'):
        raise manager_exceptions.BadParametersError(
            'Role `{0}` is a {1} and cannot be assigned as a {2}'.format(
                role_name, role['type'], expected_role_type))
Ejemplo n.º 7
0
def get_json_and_verify_params(params=None):
    params = params or []
    if request.content_type != 'application/json':
        raise manager_exceptions.UnsupportedContentTypeError(
            'Content type must be application/json')

    request_dict = request.json
    is_params_dict = isinstance(params, dict)

    def is_optional(param_name):
        return is_params_dict and params[param_name].get('optional', False)

    def check_type(param_name):
        return is_params_dict and params[param_name].get('type', None)

    for param in params:
        if param not in request_dict:
            if is_optional(param):
                continue
            raise manager_exceptions.BadParametersError(
                'Missing {0} in json request body'.format(param))

        param_type = check_type(param)
        if param_type and not isinstance(request_dict[param], param_type):
            raise manager_exceptions.BadParametersError(
                '{0} parameter is expected to be of type {1} but is of type '
                '{2}'.format(param, param_type.__name__,
                             type(request_dict[param]).__name__))
    return request_dict
Ejemplo n.º 8
0
    def _validate_location(self, request_dict):
        location = request_dict.get('location')
        if not location:
            if location == '':
                request_dict['latitude'] = None
                request_dict['longitude'] = None
            return

        # The location format is : "latitude,longitude"
        latitude, _, longitude = location.partition(',')

        # There is no comma separator
        if latitude == location:
            raise manager_exceptions.BadParametersError(
                'Invalid location `{0}`, the format is expected to be '
                '"latitude,longitude" such as "32.071072,34.787274"'.format(
                    location))

        try:
            latitude = float(latitude)
            longitude = float(longitude)
        except ValueError:
            raise manager_exceptions.BadParametersError(
                "Invalid location `{0}`, the latitude and longitude are "
                "expected to be of type float".format(location))

        if not (-90.0 <= latitude <= 90.0 and -180.0 <= longitude <= 180.0):
            raise manager_exceptions.BadParametersError(
                "Invalid location `{0}`. The latitude must be a number "
                "between -90 and 90 and the longitude between -180 and 180".
                format(location))

        request_dict['latitude'] = latitude
        request_dict['longitude'] = longitude
Ejemplo n.º 9
0
    def _extract_application_file(cls, file_server_root, application_dir,
                                  application_file_name):

        full_application_dir = os.path.join(file_server_root, application_dir)

        if application_file_name:
            application_file_name = urllib.unquote(
                application_file_name).decode('utf-8')
            application_file = os.path.join(full_application_dir,
                                            application_file_name)
            if not os.path.isfile(application_file):
                raise manager_exceptions.BadParametersError(
                    '{0} does not exist in the application '
                    'directory'.format(application_file_name))
        else:
            application_file_name = CONVENTION_APPLICATION_BLUEPRINT_FILE
            application_file = os.path.join(full_application_dir,
                                            application_file_name)
            if not os.path.isfile(application_file):
                raise manager_exceptions.BadParametersError(
                    'application directory is missing blueprint.yaml and '
                    'application_file_name query parameter was not passed')

        # return relative path from the file server root since this path
        # is appended to the file server base uri
        return application_file_name
Ejemplo n.º 10
0
    def delete(self, filters=None, pagination=None, sort=None,
               range_filters=None, **kwargs):
        """Delete events/logs connected to a certain Deployment ID."""
        if not isinstance(filters, dict) or 'type' not in filters:
            raise manager_exceptions.BadParametersError(
                'Filter by type is expected')

        if 'cloudify_event' not in filters['type']:
            raise manager_exceptions.BadParametersError(
                'At least `type=cloudify_event` filter is expected')

        executions_query = (
            db.session.query(Execution._storage_id)
            .filter(
                Execution._deployment_fk == Deployment._storage_id,
                Deployment.id == bindparam('deployment_id'),
                Execution._tenant_id == bindparam('tenant_id')
            )
        )
        params = {
            'deployment_id': filters['deployment_id'][0],
            'tenant_id': self.current_tenant.id
        }
        do_store_before = 'store_before' in filters and \
                          filters['store_before'][0].upper() == 'TRUE'

        delete_event_query = Events._apply_range_filters(
            Events._build_delete_subquery(
                Event, executions_query, params),
            Event, range_filters)
        if do_store_before:
            self._store_log_entries('events', filters['deployment_id'][0],
                                    delete_event_query.order_by(
                                        'reported_timestamp'))
        total = delete_event_query.delete(
            synchronize_session=False)

        if 'cloudify_log' in filters['type']:
            delete_log_query = Events._apply_range_filters(
                Events._build_delete_subquery(
                    Log, executions_query, params),
                Log, range_filters)
            if do_store_before:
                self._store_log_entries('logs', filters['deployment_id'][0],
                                        delete_log_query.order_by(
                                            'reported_timestamp'))
            total += delete_log_query.delete('fetch')

        metadata = {'pagination': dict(pagination, total=total)}

        # Commit bulk row deletions to database
        db.session.commit()

        # We don't really want to return all of the deleted events,
        # so it's a bit of a hack to return the deleted element count.
        return ListResult([total], metadata)
Ejemplo n.º 11
0
    def delete(self, filters=None, pagination=None, sort=None,
               range_filters=None, **kwargs):
        """Delete events/logs connected to a certain Deployment ID."""
        if not isinstance(filters, dict) or 'type' not in filters:
            raise manager_exceptions.BadParametersError(
                'Filter by type is expected')

        if 'cloudify_event' not in filters['type']:
            raise manager_exceptions.BadParametersError(
                'At least `type=cloudify_event` filter is expected')

        executions_query = (
            db.session.query(Execution._storage_id)
            .filter(
                Execution._deployment_fk == Deployment._storage_id,
                Deployment.id == bindparam('deployment_id'),
                Execution._tenant_id == bindparam('tenant_id')
            )
        )
        params = {
            'deployment_id': filters['deployment_id'][0],
            'tenant_id': self.current_tenant.id
        }

        delete_event_query = (
            db.session.query(Event)
            .filter(
                Event._execution_fk.in_(executions_query),
                Event._tenant_id == bindparam('tenant_id')
            )
            .params(**params)
        )
        total = delete_event_query.delete(synchronize_session=False)

        if 'cloudify_log' in filters['type']:
            delete_log_query = (
                db.session.query(Log)
                .filter(
                    Log._execution_fk.in_(executions_query),
                    Log._tenant_id == bindparam('tenant_id')
                )
                .params(**params)
            )
            total += delete_log_query.delete('fetch')

        metadata = {
            'pagination': dict(pagination, total=total)
        }

        # Commit bulk row deletions to database
        db.session.commit()

        # We don't really want to return all of the deleted events,
        # so it's a bit of a hack to return the deleted element count.
        return ListResult([total], metadata)
Ejemplo n.º 12
0
def verify_parameter_in_request_body(param,
                                     request_json,
                                     param_type=None,
                                     optional=False):
    if param not in request_json:
        if optional:
            return
        raise manager_exceptions.BadParametersError(
            'Missing {0} in json request body'.format(param))
    if param_type and not isinstance(request_json[param], param_type):
        raise manager_exceptions.BadParametersError(
            '{0} parameter is expected to be of type {1} but is of type '
            '{2}'.format(param, param_type.__name__,
                         type(request_json[param]).__name__))
Ejemplo n.º 13
0
    def put(self, id, phase):
        """
        Supports a newer form of deployment update, when the blueprint for the
        update has already been uploaded to the manager.
        The request should contain a blueprint id (instead of a new blueprint
        to upload)
        The inputs are now supplied as a json dict - just like in deployment
        creation.

        Note: the blueprint id of the deployment will be updated to the given
        blueprint id.
        """
        request_json = request.json
        manager, skip_install, skip_uninstall, workflow_id = \
            self._get_params_and_validate(id, request_json)
        inputs = request_json.get('inputs', {})
        blueprint_id = request_json.get('blueprint_id')
        if not isinstance(inputs, dict):
            raise manager_exceptions.BadParametersError(
                'parameter `inputs` must be of type `dict`')
        if not blueprint_id:
            raise manager_exceptions.BadParametersError(
                'Must supply the parameter `blueprint_id`')

        sm = get_storage_manager()
        blueprint = sm.get(models.Blueprint, blueprint_id)
        blueprint_dir_abs = join(config.instance.file_server_root,
                                 FILE_SERVER_BLUEPRINTS_FOLDER,
                                 blueprint.tenant_name,
                                 blueprint_id)
        deployment = sm.get(models.Deployment, id)
        deployment_dir = join(FILE_SERVER_DEPLOYMENTS_FOLDER,
                              deployment.tenant_name,
                              id)
        dep_dir_abs = join(config.instance.file_server_root, deployment_dir)
        rmtree(dep_dir_abs, ignore_errors=True)
        copytree(blueprint_dir_abs, dep_dir_abs)
        file_name = blueprint.main_file_name
        deployment.blueprint = blueprint
        sm.update(deployment)
        deployment_update = manager.stage_deployment_update(id,
                                                            deployment_dir,
                                                            file_name,
                                                            inputs)
        manager.extract_steps_from_deployment_update(deployment_update)
        return manager.commit_deployment_update(deployment_update,
                                                skip_install=skip_install,
                                                skip_uninstall=skip_uninstall,
                                                workflow_id=workflow_id)
Ejemplo n.º 14
0
def validate_and_decode_password(password):
    if not password:
        raise manager_exceptions.BadParametersError('The password is empty')

    if len(password) > 256:
        raise manager_exceptions.BadParametersError(
            'The password is too long. Maximum allowed length is 256 '
            'characters')

    if len(password) < 5:
        raise manager_exceptions.BadParametersError(
            'The password is too short. Minimum allowed length is 5 '
            'characters')

    return password
Ejemplo n.º 15
0
    def _get_params_and_validate(deployment_id, request_json):
        manager = get_deployment_updates_manager()
        skip_install = verify_and_convert_bool(
            'skip_install',
            request_json.get('skip_install', 'false'))
        skip_uninstall = verify_and_convert_bool(
            'skip_uninstall',
            request_json.get('skip_uninstall', 'false'))
        force = verify_and_convert_bool(
            'force',
            request_json.get('force', 'false'))
        workflow_id = request_json.get('workflow_id', None)

        if (skip_install or skip_uninstall) and workflow_id:
            raise manager_exceptions.BadParametersError(
                'skip_install has been set to {0}, skip uninstall has been'
                ' set to {1}, and a custom workflow {2} has been set to '
                'replace "update". However, skip_install and '
                'skip_uninstall are mutually exclusive with a custom '
                'workflow'.format(skip_install,
                                  skip_uninstall,
                                  workflow_id))
        manager.validate_no_active_updates_per_deployment(
            deployment_id=deployment_id, force=force)
        return manager, skip_install, skip_uninstall, workflow_id
Ejemplo n.º 16
0
    def patch(self, node_instance_id):
        """
        Update node instance by id
        """
        verify_json_content_type()
        if request.json.__class__ is not dict or \
                'version' not in request.json or \
                request.json['version'].__class__ is not int:

            if request.json.__class__ is not dict:
                message = 'Request body is expected to be a map containing ' \
                          'a "version" field and optionally ' \
                          '"runtimeProperties" and/or "state" fields'
            elif 'version' not in request.json:
                message = 'Request body must be a map containing a ' \
                          '"version" field'
            else:
                message = \
                    "request body's 'version' field must be an int but" \
                    " is of type {0}".format(request.json['version']
                                             .__class__.__name__)
            raise manager_exceptions.BadParametersError(message)

        node = models.DeploymentNodeInstance(
            id=node_instance_id,
            node_id=None,
            relationships=None,
            host_id=None,
            deployment_id=None,
            runtime_properties=request.json.get('runtime_properties'),
            state=request.json.get('state'),
            version=request.json['version'])
        get_storage_manager().update_node_instance(node)
        return responses.NodeInstance(**get_storage_manager(
        ).get_node_instance(node_instance_id).to_dict())
Ejemplo n.º 17
0
 def post(self, snapshot_id):
     _verify_no_multi_node_cluster(action="restore snapshot")
     request_dict = rest_utils.get_json_and_verify_params(
         {'recreate_deployments_envs'})
     recreate_deployments_envs = rest_utils.verify_and_convert_bool(
         'recreate_deployments_envs',
         request_dict['recreate_deployments_envs'])
     bypass_maintenance = is_bypass_maintenance_mode()
     force = rest_utils.verify_and_convert_bool('force',
                                                request_dict['force'])
     restore_certificates = rest_utils.verify_and_convert_bool(
         'restore_certificates',
         request_dict.get('restore_certificates', 'false'))
     no_reboot = rest_utils.verify_and_convert_bool(
         'no_reboot', request_dict.get('no_reboot', 'false'))
     if no_reboot and not restore_certificates:
         raise manager_exceptions.BadParametersError(
             '`no_reboot` is only relevant when `restore_certificates` is '
             'activated')
     default_timeout_sec = 300
     request_timeout = request_dict.get('timeout', default_timeout_sec)
     timeout = rest_utils.convert_to_int(request_timeout)
     execution = get_resource_manager().restore_snapshot(
         snapshot_id, recreate_deployments_envs, force, bypass_maintenance,
         timeout, restore_certificates, no_reboot)
     return execution, 200
Ejemplo n.º 18
0
def _verify_status_report_schema(node_id, report):
    if not (_are_keys_in_dict(report['report'], [STATUS, SERVICES])
            and report['report'][STATUS]
            in [ServiceStatus.HEALTHY, ServiceStatus.FAIL]):
        raise manager_exceptions.BadParametersError(
            'The status report for {0} is malformed and discarded'.format(
                node_id))
Ejemplo n.º 19
0
 def _validate_reinstall_list(self, reinstall, add, remove, dep_update):
     """validate node-instances explicitly supplied to reinstall list exist
     and are not about to be installed or uninstalled in this update"""
     node_instances = self.sm.list(
         models.NodeInstance,
         filters={'deployment_id': dep_update.deployment_id},
         get_all_results=True)
     node_instances_ids = [n.id for n in node_instances]
     add_conflict = [n for n in reinstall if n in add]
     remove_conflict = [n for n in reinstall if n in remove]
     not_existing = [n for n in reinstall if n not in node_instances_ids]
     msg = 'Invalid reinstall list supplied.'
     if not_existing:
         msg += '\nFollowing node instances do not exist in this ' \
                'deployment: ' + ', '.join(not_existing)
     if add_conflict:
         msg += '\nFollowing node instances are just being added in the ' \
                'update: ' + ', '.join(add_conflict)
     if remove_conflict:
         msg += '\nFollowing node instances are just being removed in ' \
                'the update: ' + ', '.join(remove_conflict)
     if any([not_existing, add_conflict, remove_conflict]):
         dep_update.state = STATES.FAILED
         self.sm.update(dep_update)
         raise manager_exceptions.BadParametersError(msg)
Ejemplo n.º 20
0
    def _apply_sort(query, sort):
        """Apply sorting criteria.

        Sorting will be rejected if the field doesn't match any of the column
        names that has been selected for the query. Note that the query
        involves two models at the same time, it is not possible to just check
        a model.

        :param query: Query in which the sorting should be applied
        :type query: :class:`sqlalchemy.orm.query.Query`
        :param sort: Sorting criteria passed as a request argument
        :type sort: dict(str, str)
        :returns: Query with sorting criteria applied
        :rtype: :class:`sqlalchemy.orm.query.Query`

        """
        column_names = set(column_description['name']
                           for column_description in query.column_descriptions)
        for field, order in sort.items():
            # Drop `@` prefix for compatibility
            # with old Elasticsearch based implementation
            field = field.lstrip('@')
            if field not in column_names:
                raise manager_exceptions.BadParametersError(
                    'Unknown field to sort by: {}'.format(field))

            order_func = asc if order == 'asc' else desc
            query = query.order_by(order_func(field))
        return query
Ejemplo n.º 21
0
    def _apply_range_filters(query, model, range_filters):
        """Apply range filters to query.

        :param query: Query in which the filtering should be applied
        :type query: :class:`sqlalchemy.orm.query.Query`
        :param model: Model to use to apply the filtering
        :type model:
            :class:`manager_rest.storage.resource_models.Event`
            :class:`manager_rest.storage.resource_models.Log`
        :param range_filters: Range filters passed as a request argument
        :type range_filters: dict(str, dict(str))
        :returns: Query with filtering applied
        :rtype: :class:`sqlalchemy.orm.query.Query`

        """
        for field, range_filter in range_filters.items():
            # Drop `@` prefix for compatibility
            # with old Elasticsearch based implementation
            field = field.lstrip('@')
            if not hasattr(model, field):
                raise manager_exceptions.BadParametersError(
                    'Unknown field to filter by range: {}'.format(field))
            query = Events._apply_range_filter(query, model, field,
                                               range_filter)
        return query
Ejemplo n.º 22
0
    def receive_uploaded_data(self, data_id=None, **kwargs):
        blueprint_url = None
        visibility = kwargs.get(_VISIBILITY, None)
        labels = kwargs.get('labels', None)
        override_failed_blueprint = kwargs.get('override_failed', False)

        args = get_args_and_verify_arguments([
            Argument('private_resource', type=boolean),
            Argument('application_file_name', default='')
        ])

        # Handle importing blueprint through url
        if self._get_data_url_key() in request.args:
            if request.data or \
                    'Transfer-Encoding' in request.headers or \
                    'blueprint_archive' in request.files:
                raise manager_exceptions.BadParametersError(
                    "Can pass {0} as only one of: URL via query parameters, "
                    "request body, multi-form or "
                    "chunked.".format(self._get_kind()))
            blueprint_url = request.args[self._get_data_url_key()]

        visibility = get_resource_manager().get_resource_visibility(
            Blueprint, data_id, visibility, args.private_resource)

        new_blueprint = self._prepare_and_process_doc(
            data_id,
            visibility,
            blueprint_url,
            application_file_name=args.application_file_name,
            override_failed_blueprint=override_failed_blueprint,
            labels=labels)
        return new_blueprint, 201
Ejemplo n.º 23
0
    def _update_case_insensitive(column, value):
        """Check if the column in question should be case insensitive, and
        if so, make sure the column (and the value) will be converted to lower
        case

        :return: The updated column and value in a (c, v) tuple
        """
        is_case_insensitive = getattr(column, 'is_ci', False)
        if not is_case_insensitive:
            return column, value

        # Adding a label to preserve the column name
        column = func.lower(column).label(column.key)
        try:
            if isinstance(value, (list, tuple)):
                value = [v.lower() for v in value]
            else:
                value = value.lower()
        except AttributeError:
            raise manager_exceptions.BadParametersError(
                'Incorrect param passed to column `{0}`: {1}. '
                'Param type should be string'.format(
                    column.name, value
                )
            )

        return column, value
Ejemplo n.º 24
0
def _validate_allowed_substitutions(param_name, param_value, allowed):
    if allowed is None or param_value is None:
        current_app.logger.debug(
            'Empty value or no allowed substitutions '
            'defined for %s, skipping.', param_name)
        return
    f = string.Formatter()
    invalid = []
    current_app.logger.debug('Checking allowed substitutions for %s (%s)',
                             param_name, ','.join(allowed))
    current_app.logger.debug('Value is: %s', param_value)
    for _, field, _, _ in f.parse(param_value):
        if field is None:
            # This will occur at the end of a string unless the string ends at
            # the end of a field
            continue
        current_app.logger.debug('Found %s', field)
        if field not in allowed:
            current_app.logger.debug('Field not valid.')
            invalid.append(field)
    if invalid:
        raise manager_exceptions.BadParametersError(
            '{candidate_name} has invalid parameters.\n'
            'Invalid parameters found: {invalid}.\n'
            'Allowed: {allowed}'.format(
                candidate_name=param_name,
                invalid=', '.join(invalid),
                allowed=', '.join(allowed),
            )
        )
Ejemplo n.º 25
0
    def post(self):
        """Execute a workflow"""
        verify_json_content_type()
        request_json = request.json
        verify_parameter_in_request_body('deployment_id', request_json)
        verify_parameter_in_request_body('workflow_id', request_json)

        allow_custom_parameters = verify_and_convert_bool(
            'allow_custom_parameters',
            request_json.get('allow_custom_parameters', 'false'))
        force = verify_and_convert_bool('force',
                                        request_json.get('force', 'false'))

        deployment_id = request.json['deployment_id']
        workflow_id = request.json['workflow_id']
        parameters = request.json.get('parameters', None)

        if parameters is not None and parameters.__class__ is not dict:
            raise manager_exceptions.BadParametersError(
                "request body's 'parameters' field must be a dict but"
                " is of type {0}".format(parameters.__class__.__name__))

        execution = get_blueprints_manager().execute_workflow(
            deployment_id,
            workflow_id,
            parameters=parameters,
            allow_custom_parameters=allow_custom_parameters,
            force=force)
        return responses.Execution(**execution.to_dict()), 201
Ejemplo n.º 26
0
    def patch(self, node_instance_id, **kwargs):
        """Update node instance by id."""
        request_dict = get_json_and_verify_params({'version': {'type': int}})

        if not isinstance(request.json, collections.Mapping):
            raise manager_exceptions.BadParametersError(
                'Request body is expected to be a map containing a "version" '
                'field and optionally "runtimeProperties" and/or "state" '
                'fields')

        # Added for backwards compatibility with older client versions that
        # had version=0 by default
        version = request_dict['version'] or 1

        instance = get_storage_manager().get(models.NodeInstance,
                                             node_instance_id,
                                             locking=True)
        if instance.version > version:
            raise manager_exceptions.ConflictError(
                'Node instance update conflict [current version={0}, '
                'update version={1}]'.format(instance.version, version))
        # Only update if new values were included in the request
        instance.runtime_properties = request_dict.get(
            'runtime_properties', instance.runtime_properties)
        instance.state = request_dict.get('state', instance.state)
        return get_storage_manager().update(instance)
Ejemplo n.º 27
0
    def post(self, **kwargs):
        """Execute a workflow"""
        request_dict = get_json_and_verify_params(
            {'deployment_id', 'workflow_id'})

        allow_custom_parameters = verify_and_convert_bool(
            'allow_custom_parameters',
            request_dict.get('allow_custom_parameters', 'false'))
        force = verify_and_convert_bool('force',
                                        request_dict.get('force', 'false'))
        dry_run = verify_and_convert_bool('dry_run',
                                          request_dict.get('dry_run', 'false'))
        queue = verify_and_convert_bool('queue',
                                        request_dict.get('queue', 'false'))

        deployment_id = request_dict['deployment_id']
        workflow_id = request_dict['workflow_id']
        parameters = request_dict.get('parameters', None)

        if parameters is not None and parameters.__class__ is not dict:
            raise manager_exceptions.BadParametersError(
                "request body's 'parameters' field must be a dict but"
                " is of type {0}".format(parameters.__class__.__name__))

        bypass_maintenance = is_bypass_maintenance_mode()
        execution = get_resource_manager().execute_workflow(
            deployment_id,
            workflow_id,
            parameters=parameters,
            allow_custom_parameters=allow_custom_parameters,
            force=force,
            dry_run=dry_run,
            bypass_maintenance=bypass_maintenance,
            queue=queue)
        return execution, 201
Ejemplo n.º 28
0
 def _move_archive_to_uploaded_dir(self,
                                   data_id,
                                   root_path,
                                   archive_path,
                                   dest_file_name=None):
     if not os.path.exists(archive_path):
         raise RuntimeError("Archive [{0}] doesn't exist - Cannot move "
                            "archive to uploaded {1}s "
                            "directory".format(archive_path,
                                               self._get_kind()))
     uploaded_dir = os.path.join(root_path, self._get_target_dir_path(),
                                 data_id)
     if not os.path.isdir(uploaded_dir):
         os.makedirs(uploaded_dir)
     current_app.logger.info(
         'uploading archive to: {0}'.format(uploaded_dir))
     if os.path.isfile(archive_path):
         if not dest_file_name:
             try:
                 archive_type = self._get_archive_type(archive_path)
             except ArchiveTypeError:
                 raise manager_exceptions.BadParametersError(
                     'Blueprint archive is of an unrecognized format. '
                     'Supported formats are: {0}'.format(
                         SUPPORTED_ARCHIVE_TYPES))
             dest_file_name = '{0}.{1}'.format(data_id, archive_type)
         shutil.move(archive_path, os.path.join(uploaded_dir,
                                                dest_file_name))
     else:
         for item in os.listdir(archive_path):
             shutil.copy(os.path.join(archive_path, item), uploaded_dir)
         shutil.rmtree(archive_path)
Ejemplo n.º 29
0
 def post(self, snapshot_id):
     request_dict = rest_utils.get_json_and_verify_params(
         {'recreate_deployments_envs'})
     recreate_deployments_envs = rest_utils.verify_and_convert_bool(
         'recreate_deployments_envs',
         request_dict['recreate_deployments_envs'])
     force = rest_utils.verify_and_convert_bool('force',
                                                request_dict['force'])
     restore_certificates = rest_utils.verify_and_convert_bool(
         'restore_certificates',
         request_dict.get('restore_certificates', 'false'))
     no_reboot = rest_utils.verify_and_convert_bool(
         'no_reboot', request_dict.get('no_reboot', 'false'))
     ignore_plugin_failure = \
         rest_utils.verify_and_convert_bool(
             'ignore_plugin_failure',
             request_dict.get('ignore_plugin_failure', 'false')
         )
     if no_reboot and not restore_certificates:
         raise manager_exceptions.BadParametersError(
             '`no_reboot` is only relevant when `restore_certificates` is '
             'activated')
     default_timeout_sec = 300
     request_timeout = request_dict.get('timeout', default_timeout_sec)
     timeout = rest_utils.convert_to_int(request_timeout)
     execution = get_resource_manager().restore_snapshot(
         snapshot_id, recreate_deployments_envs, force, True, timeout,
         restore_certificates, no_reboot, ignore_plugin_failure)
     return execution, 200
Ejemplo n.º 30
0
    def _commit(deployment_id):
        manager = get_deployment_updates_manager()
        request_json = request.args
        skip_install = verify_and_convert_bool(
            'skip_install', request_json.get('skip_install', 'false'))
        skip_uninstall = verify_and_convert_bool(
            'skip_uninstall', request_json.get('skip_uninstall', 'false'))
        force = verify_and_convert_bool('force',
                                        request_json.get('force', 'false'))
        workflow_id = request_json.get('workflow_id', None)

        if (skip_install or skip_uninstall) and workflow_id:
            raise manager_exceptions.BadParametersError(
                'skip_install has been set to {0}, skip uninstall has been'
                ' set to {1}, and a custom workflow {2} has been set to '
                'replace "update". However, skip_install and '
                'skip_uninstall are mutually exclusive with a custom '
                'workflow'.format(skip_install, skip_uninstall, workflow_id))

        manager.validate_no_active_updates_per_deployment(
            deployment_id=deployment_id, force=force)

        deployment_update, _ = \
            UploadedBlueprintsDeploymentUpdateManager(). \
            receive_uploaded_data(deployment_id)

        manager.extract_steps_from_deployment_update(deployment_update)

        return manager.commit_deployment_update(deployment_update,
                                                skip_install=skip_install,
                                                skip_uninstall=skip_uninstall,
                                                workflow_id=workflow_id)