def put(self, name):
        """Update a config value.

        Settings which have is_editable set to False, can only be edited
        when passing the force flag.
        If a schema is specified for the given setting, the new value
        must validate.
        """
        sm = get_storage_manager()
        data = rest_utils.get_json_and_verify_params({
            'value': {},
            'force': {
                'type': bool,
                'optional': True
            }
        })
        value = data['value']
        force = data.get('force', False)

        inst = sm.get(models.Config, None, filters={'name': name})
        if not inst.is_editable and not force:
            raise ConflictError('{0} is not editable'.format(name))
        if inst.schema:
            try:
                jsonschema.validate(value, inst.schema)
            except jsonschema.ValidationError as e:
                raise ConflictError(e.args[0])
        inst.value = value
        inst.updated_at = datetime.now()
        inst.updated_by = current_user
        sm.update(inst)
        return inst
Esempio n. 2
0
 def put(self, blueprint_id, **kwargs):
     """
     Upload a blueprint (id specified)
     """
     rest_utils.validate_inputs({'blueprint_id': blueprint_id})
     visibility = rest_utils.get_visibility_parameter(
         optional=True,
         is_argument=True,
         valid_values=VisibilityState.STATES)
     # Fail fast if trying to upload a duplicate blueprint
     current_tenant = request.headers.get('tenant')
     if visibility == VisibilityState.GLOBAL:
         existing_duplicates = get_storage_manager().list(
             models.Blueprint, filters={'id': blueprint_id})
         if existing_duplicates:
             raise IllegalActionError(
                 "Can't set or create the resource `{0}`, it's visibility "
                 "can't be global because it also exists in other "
                 "tenants".format(blueprint_id))
     else:
         existing_duplicates = get_storage_manager().list(models.Blueprint,
                                                          filters={
                                                              'id':
                                                              blueprint_id,
                                                              'tenant_name':
                                                              current_tenant
                                                          })
         if existing_duplicates:
             raise ConflictError(
                 'blueprint with id={0} already exists on tenant {1} or '
                 'with global visibility'.format(blueprint_id,
                                                 current_tenant))
     return UploadedBlueprintsManager().\
         receive_uploaded_data(data_id=blueprint_id,
                               visibility=visibility)
Esempio n. 3
0
    def put(self, blueprint_id, **kwargs):
        """
        Upload a blueprint (id specified)
        """
        rest_utils.validate_inputs({'blueprint_id': blueprint_id})
        args = get_args_and_verify_arguments([
            Argument('async_upload', type=boolean, default=False),
            Argument('labels')
        ])
        async_upload = args.async_upload
        visibility = rest_utils.get_visibility_parameter(
            optional=True,
            is_argument=True,
            valid_values=VisibilityState.STATES)
        labels = self._get_labels_from_args(args)
        # Fail fast if trying to upload a duplicate blueprint.
        # Allow overriding an existing blueprint which failed to upload
        current_tenant = request.headers.get('tenant')
        override_failed = False

        if visibility == VisibilityState.GLOBAL:
            existing_duplicates = get_storage_manager().list(
                models.Blueprint, filters={'id': blueprint_id})
            if existing_duplicates:
                if existing_duplicates[0].state in \
                        BlueprintUploadState.FAILED_STATES:
                    override_failed = True
                else:
                    raise IllegalActionError(
                        "Can't set or create the resource `{0}`, it's "
                        "visibility can't be global because it also exists in "
                        "other tenants".format(blueprint_id))
        else:
            existing_duplicates = get_storage_manager().list(models.Blueprint,
                                                             filters={
                                                                 'id':
                                                                 blueprint_id,
                                                                 'tenant_name':
                                                                 current_tenant
                                                             })
            if existing_duplicates:
                if existing_duplicates[0].state in \
                        BlueprintUploadState.FAILED_STATES:
                    override_failed = True
                else:
                    raise ConflictError(
                        'blueprint with id={0} already exists on tenant {1} '
                        'or with global visibility'.format(
                            blueprint_id, current_tenant))
        response = UploadedBlueprintsManager().\
            receive_uploaded_data(data_id=blueprint_id,
                                  visibility=visibility,
                                  override_failed=override_failed,
                                  labels=labels)
        if not async_upload:
            sm = get_storage_manager()
            blueprint, _ = response
            response = rest_utils.get_uploaded_blueprint(sm, blueprint)
        return response
Esempio n. 4
0
    def update_db(self, config_dict, force=False):
        """
        Update the config table in the DB with values passed in the
        config dictionary parameter
        """
        from manager_rest.storage import models

        engine = create_engine(self.db_url)
        session = orm.Session(bind=engine)
        stored_configs = session.query(models.Config).all()

        config_mappings = []
        for name, value in config_dict.items():
            if name == 'ldap_ca_cert':
                cert = session.query(models.Certificate).filter_by(
                    name=LDAP_CA_NAME, ).one_or_none() or models.Certificate()
                cert.name = LDAP_CA_NAME
                cert.value = value
                session.add(cert)
                continue
            entry = self._find_entry(stored_configs, name)
            if not entry.is_editable and not force:
                raise ConflictError('{0} is not editable'.format(entry.name))
            if entry.schema:
                try:
                    jsonschema.validate(config_dict[entry.name], entry.schema)
                except jsonschema.ValidationError as e:
                    raise ConflictError(
                        'Error validating {name}: {err}'.format(name=name,
                                                                err=e.args[0]))
            config_mappings.append({
                'name': entry.name,
                'scope': entry.scope,
                'value': value,
                'updated_at': datetime.now(),
                '_updater_id': current_user.id,
            })
        session.bulk_update_mappings(models.Config, config_mappings)
        session.commit()
        session.close()
        engine.dispose()

        for name, value in config_dict.items():
            setattr(self, name, value)
Esempio n. 5
0
    def validate_no_active_updates_per_blueprint(self,
                                                 blueprint_id,
                                                 force=False):
        active_updates = self.list_plugins_updates(filters={
            'blueprint_id': blueprint_id,
            'state': ACTIVE_STATES
        }).items
        if not active_updates:
            return

        if not force:
            raise ConflictError(
                'There are plugins updates still active, update IDs: '
                '{0}'.format(', '.join(u.id for u in active_updates)))

        execs_to_updates = {
            u.execution_id: u
            for u in active_updates if u.execution_id
        }
        running_updates = [
            execs_to_updates[execution.id]
            for execution in self.sm.list(models.Execution,
                                          filters={
                                              'id': execs_to_updates.keys()
                                          }).items
            if execution.status not in ExecutionState.END_STATES
        ]

        if running_updates:
            raise ConflictError(
                'There are plugins updates still active; the "force" flag '
                'was used yet these updates have actual executions running '
                'update IDs: {0}'.format(', '.join(u.id
                                                   for u in running_updates)))
        else:
            # the active updates aren't really active - either their
            # executions were failed/cancelled, or the update failed at
            # the finalizing stage.
            # updating their states to failed and continuing.
            for plugins_update in active_updates:
                plugins_update.state = STATES.FAILED
                self.sm.update(plugins_update)
Esempio n. 6
0
    def validate_no_active_updates_per_blueprint(self, blueprint_id):
        active_updates = self.list_plugins_updates(filters={
            'blueprint_id': blueprint_id,
            'state': ACTIVE_STATES
        }).items
        if not active_updates:
            return

        raise ConflictError(
            'There are plugins updates still active, update IDs: '
            '{0}'.format(', '.join(u.id for u in active_updates)))
Esempio n. 7
0
    def update_db(self, config_dict, force=False):
        """
        Update the config table in the DB with values passed in the
        config dictionary parameter
        """
        from manager_rest.storage import models
        from sqlalchemy import create_engine, orm

        engine = create_engine(self.db_url)
        session = orm.Session(bind=engine)
        stored_configs = session.query(models.Config).all()

        config_mappings = []
        for name, value in config_dict.items():
            entry = self._find_entry(stored_configs, name)
            if not entry.is_editable and not force:
                raise ConflictError('{0} is not editable'.format(entry.name))
            if entry.schema:
                try:
                    jsonschema.validate(config_dict[entry.name], entry.schema)
                except jsonschema.ValidationError as e:
                    raise ConflictError(e.args[0])
            config_mappings.append({
                'name': entry.name,
                'scope': entry.scope,
                'value': value,
                'updated_at': datetime.now(),
                '_updater_id': current_user.id,
            })
        session.bulk_update_mappings(models.Config, config_mappings)
        session.commit()
        session.close()
        engine.dispose()

        for name, value in config_dict.items():
            setattr(self, name, value)
Esempio n. 8
0
    def patch(self, blueprint_id, **kwargs):
        """
        Update a blueprint.

        Used for updating the blueprint's state (and error) while uploading,
        and updating the blueprint's other attributes upon a successful upload.
        This method is for internal use only.
        """
        if not request.json:
            raise IllegalActionError('Update a blueprint request must include '
                                     'at least one parameter to update')

        request_schema = {
            'plan': {
                'type': dict,
                'optional': True
            },
            'description': {
                'type': text_type,
                'optional': True
            },
            'main_file_name': {
                'type': text_type,
                'optional': True
            },
            'visibility': {
                'type': text_type,
                'optional': True
            },
            'state': {
                'type': text_type,
                'optional': True
            },
            'error': {
                'type': text_type,
                'optional': True
            },
            'error_traceback': {
                'type': text_type,
                'optional': True
            },
            'labels': {
                'type': list,
                'optional': True
            }
        }
        request_dict = rest_utils.get_json_and_verify_params(request_schema)

        invalid_params = set(request_dict.keys()) - set(request_schema.keys())
        if invalid_params:
            raise BadParametersError("Unknown parameters: {}".format(
                ','.join(invalid_params)))
        sm = get_storage_manager()
        rm = get_resource_manager()
        blueprint = sm.get(models.Blueprint, blueprint_id)

        # if finished blueprint validation - cleanup DB entry
        # and uploaded blueprints folder
        if blueprint.state == BlueprintUploadState.VALIDATING:
            uploaded_blueprint_path = join(
                config.instance.file_server_root,
                FILE_SERVER_UPLOADED_BLUEPRINTS_FOLDER, blueprint.tenant.name,
                blueprint.id)
            remove(uploaded_blueprint_path)
            sm.delete(blueprint)
            return blueprint

        # set blueprint visibility
        visibility = request_dict.get('visibility')
        if visibility:
            if visibility not in VisibilityState.STATES:
                raise BadParametersError(
                    "Invalid visibility: `{0}`. Valid visibility's values "
                    "are: {1}".format(visibility, VisibilityState.STATES))
            blueprint.visibility = visibility

        # set other blueprint attributes.
        if 'plan' in request_dict:
            blueprint.plan = request_dict['plan']
        if 'description' in request_dict:
            blueprint.description = request_dict['description']
        if 'main_file_name' in request_dict:
            blueprint.main_file_name = request_dict['main_file_name']
        provided_labels = request_dict.get('labels')

        if request_dict.get('plan'):
            dsl_labels = request_dict['plan'].get('labels', {})
            csys_obj_parents = dsl_labels.get('csys-obj-parent')
            if csys_obj_parents:
                dep_parents = csys_obj_parents['values']
                missing_parents = rm.get_missing_deployment_parents(
                    dep_parents)
                if missing_parents:
                    raise DeploymentParentNotFound(
                        'Blueprint {0}: is referencing deployments'
                        ' using label `csys-obj-parent` that does not exist, '
                        'make sure that deployment(s) {1} exist before '
                        'creating blueprint'.format(blueprint.id,
                                                    ','.join(missing_parents)))
        # set blueprint state
        state = request_dict.get('state')
        if state:
            if state not in BlueprintUploadState.STATES:
                raise BadParametersError(
                    "Invalid state: `{0}`. Valid blueprint state values are: "
                    "{1}".format(state, BlueprintUploadState.STATES))
            if (state != BlueprintUploadState.UPLOADED
                    and provided_labels is not None):
                raise ConflictError(
                    'Blueprint labels can be created only if the provided '
                    'blueprint state is {0}'.format(
                        BlueprintUploadState.UPLOADED))

            blueprint.state = state
            blueprint.error = request_dict.get('error')
            blueprint.error_traceback = request_dict.get('error_traceback')

            # On finalizing the blueprint upload, extract archive to file
            # server
            if state == BlueprintUploadState.UPLOADED:
                UploadedBlueprintsManager(). \
                    extract_blueprint_archive_to_file_server(
                        blueprint_id=blueprint_id,
                        tenant=blueprint.tenant.name)
                _create_blueprint_labels(blueprint, provided_labels)

            # If failed for any reason, cleanup the blueprint archive from
            # server
            elif state in BlueprintUploadState.FAILED_STATES:
                UploadedBlueprintsManager(). \
                    cleanup_blueprint_archive_from_file_server(
                        blueprint_id=blueprint_id,
                        tenant=blueprint.tenant.name)
        else:  # Updating the blueprint not as part of the upload process
            if provided_labels is not None:
                if blueprint.state != BlueprintUploadState.UPLOADED:
                    raise ConflictError(
                        'Blueprint labels can only be updated if the blueprint'
                        ' was uploaded successfully')

                rm = get_resource_manager()
                labels_list = rest_utils.get_labels_list(provided_labels)
                rm.update_resource_labels(models.BlueprintLabel, blueprint,
                                          labels_list)

        blueprint.updated_at = get_formatted_timestamp()
        return sm.update(blueprint)