def update(self, req, body, package_id): """List of allowed changes: { "op": "add", "path": "/tags", "value": [ "foo", "bar" ] } { "op": "add", "path": "/categories", "value": [ "foo", "bar" ] } { "op": "remove", "path": "/tags" } { "op": "remove", "path": "/categories" } { "op": "replace", "path": "/tags", "value": ["foo", "bar"] } { "op": "replace", "path": "/is_public", "value": true } { "op": "replace", "path": "/description", "value":"New description" } { "op": "replace", "path": "/name", "value": "New name" } """ policy.check("modify_package", req.context, {'package_id': package_id}) pkg_to_update = db_api.package_get(package_id, req.context) if pkg_to_update.is_public: policy.check("manage_public_package", req.context) _check_content_type(req, 'application/murano-packages-json-patch') if not isinstance(body, list): msg = _('Request body must be a JSON array of operation objects.') LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) for change in body: if 'is_public' in change['path']: if change['value'] is True and not pkg_to_update.is_public: policy.check('publicize_package', req.context) if 'name' in change['path']: if len(change['value']) > 80: msg = _('Package name should be 80 characters maximum') LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) package = db_api.package_update(package_id, body, req.context) return package.to_dict()
def validate_quotes(value): """Validate filter values Validation opening/closing quotes in the expression. """ open_quotes = True count_backslash_in_row = 0 for i in range(len(value)): if value[i] == '"': if count_backslash_in_row % 2: continue if open_quotes: if i and value[i - 1] != ',': msg = _("Invalid filter value %s. There is no comma " "before opening quotation mark.") % value raise ValueError(msg) else: if i + 1 != len(value) and value[i + 1] != ",": msg = _("Invalid filter value %s. There is no comma " "after opening quotation mark.") % value raise ValueError(msg) open_quotes = not open_quotes elif value[i] == '\\': count_backslash_in_row += 1 else: count_backslash_in_row = 0 if not open_quotes: msg = _("Invalid filter value %s. The quote is not closed.") % value raise ValueError(msg) return True
def update(self, request, environment_id, body): LOG.debug('Environments:Update <Id: {0}, ' 'Body: {1}>'.format(environment_id, body)) target = {"environment_id": environment_id} policy.check('update_environment', request.context, target) session = db_session.get_session() environment = session.query(models.Environment).get(environment_id) if environment is None: LOG.info(_LI('Environment <EnvId {0}> not ' 'found').format(environment_id)) raise exc.HTTPNotFound if environment.tenant_id != request.context.tenant: LOG.info(_LI('User is not authorized to access ' 'this tenant resources.')) raise exc.HTTPUnauthorized LOG.debug('ENV NAME: {0}>'.format(body['name'])) if VALID_NAME_REGEX.match(str(body['name'])): try: environment.update(body) environment.save(session) except db_exc.DBDuplicateEntry: msg = _('Environment with specified name already exists') LOG.exception(msg) raise exc.HTTPConflict(explanation=msg) else: msg = _('Environment name must contain only alphanumeric ' 'or "_-." characters, must start with alpha') LOG.error(msg) raise exc.HTTPClientError(explanation=msg) return environment.to_dict()
def upload(self, req, body=None): """Upload new file archive for the new package together with package metadata. """ policy.check("upload_package", req.context) _check_content_type(req, 'multipart/form-data') file_obj, package_meta = _validate_body(body) if package_meta: try: jsonschema.validate(package_meta, schemas.PKG_UPLOAD_SCHEMA) except jsonschema.ValidationError as e: msg = _("Package schema is not valid: {reason}").format( reason=e) LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) else: package_meta = {} if package_meta.get('is_public'): policy.check('publicize_package', req.context) with tempfile.NamedTemporaryFile(delete=False) as tempf: LOG.debug("Storing package archive in a temporary file") content = file_obj.file.read() if not content: msg = _("Uploading file can't be empty") LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) tempf.write(content) package_meta['archive'] = content try: with load_utils.load_from_file(tempf.name, target_dir=None, drop_dir=True) as pkg_to_upload: # extend dictionary for update db for k, v in six.iteritems(PKG_PARAMS_MAP): if hasattr(pkg_to_upload, k): package_meta[v] = getattr(pkg_to_upload, k) if len(package_meta['name']) > 80: msg = _('Package name should be 80 characters maximum') LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) try: package = db_api.package_upload(package_meta, req.context.tenant) except db_exc.DBDuplicateEntry: msg = _('Package with specified full ' 'name is already registered') LOG.exception(msg) raise exc.HTTPConflict(msg) return package.to_dict() except pkg_exc.PackageLoadError as e: msg = _("Couldn't load package from file: {reason}").format( reason=e) LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) finally: LOG.debug("Deleting package archive temporary file") os.remove(tempf.name)
def _get_category_filters(req): query_params = {} valid_query_params = ['sort_keys', 'sort_dir', 'limit', 'marker'] for key, value in req.GET.items(): if key not in valid_query_params: raise exc.HTTPBadRequest( _('Bad value passed to filter. ' 'Got {key}, exected:{valid}').format( key=key, valid=', '.join(valid_query_params))) if key == 'sort_keys': available_sort_keys = [ 'name', 'created', 'updated', 'package_count', 'id' ] value = [v.strip() for v in value.split(',')] for sort_key in value: if sort_key not in available_sort_keys: raise exc.HTTPBadRequest(explanation=_( 'Invalid sort key: {sort_key}. ' 'Must be one of the following: ' '{available}').format( sort_key=sort_key, available=', '.join(available_sort_keys))) if key == 'sort_dir': if value not in ['asc', 'desc']: msg = _('Invalid sort direction: {0}').format(value) raise exc.HTTPBadRequest(explanation=msg) query_params[key] = value return query_params
def create(self, request, body): """It creates the env template from the payload obtaining. This payload can contain just the template name, or include also service information. :param request: the operation request. :param body: the env template description :return: the description of the created template. """ LOG.debug('EnvTemplates:Create <Body {body}>'.format(body=body)) policy.check('create_env_template', request.context) try: LOG.debug( 'ENV TEMP NAME: {templ_name}>'.format(templ_name=body['name'])) if not envs_api.VALID_NAME_REGEX.match(str(body['name'])): msg = _('Environment Template must contain only alphanumeric ' 'or "_-." characters, must start with alpha') LOG.error(msg) raise exc.HTTPBadRequest(msg) except Exception: msg = _('Env template body is incorrect') LOG.exception(msg) raise exc.HTTPClientError(msg) if len(body['name']) > 255: msg = _('Environment Template name should be 255 characters ' 'maximum') LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) try: template = env_temps.EnvTemplateServices.create( body.copy(), request.context.tenant) return template.to_dict() except db_exc.DBDuplicateEntry: msg = _('Env Template with specified name already exists') LOG.exception(msg) raise exc.HTTPConflict(msg)
def _validate_change(self, change): change_path = change['path'][0] change_op = change['op'] allowed_methods = self.allowed_operations.get(change_path) if not allowed_methods: msg = _("Attribute '{0}' is invalid").format(change_path) raise webob.exc.HTTPForbidden(explanation=six.text_type(msg)) if change_op not in allowed_methods: msg = _("Method '{method}' is not allowed for a path with name " "'{name}'. Allowed operations are: " "'{ops}'").format(method=change_op, name=change_path, ops=', '.join(allowed_methods)) raise webob.exc.HTTPForbidden(explanation=six.text_type(msg)) property_to_update = {change_path: change['value']} try: jsonschema.validate(property_to_update, schemas.PKG_UPDATE_SCHEMA) except jsonschema.ValidationError as e: LOG.error(_LE("Schema validation error occured: {error}") .format(error=e)) raise webob.exc.HTTPBadRequest(explanation=e.message)
def create(self, request, body): LOG.debug('Environments:Create <Body {body}>'.format(body=body)) policy.check('create_environment', request.context) if not body.get('name'): msg = _('Please, specify a name of the environment to create') LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) name = unicode(body['name']) if len(name) > 255: msg = _('Environment name should be 255 characters maximum') LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) if VALID_NAME_REGEX.match(name): try: environment = envs.EnvironmentServices.create( body.copy(), request.context) except db_exc.DBDuplicateEntry: msg = _('Environment with specified name already exists') LOG.exception(msg) raise exc.HTTPConflict(explanation=msg) else: msg = _('Environment name must contain only alphanumericor "_-." ' 'characters, must start with alpha') LOG.exception(msg) raise exc.HTTPClientError(explanation=msg) return environment.to_dict()
def __inner(self, request, *args, **kwargs): if hasattr(request, 'context') and not request.context.session: msg = _('X-Configuration-Session header which indicates' ' to the session is missed') LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) session_id = request.context.session unit = db_session.get_session() session = unit.query(models.Session).get(session_id) if session is None: msg = _('Session <SessionId {0}> is not found').format(session_id) LOG.error(msg) raise exc.HTTPNotFound(explanation=msg) if not sessions.SessionServices.validate(session): msg = _('Session <SessionId {0}> ' 'is invalid: environment has been updated or ' 'updating right now with other session').format(session_id) LOG.error(msg) raise exc.HTTPForbidden(explanation=msg) if session.state == states.SessionState.DEPLOYING: msg = _('Session <SessionId {0}> is already in deployment state' ).format(session_id) raise exc.HTTPForbidden(explanation=msg) return func(self, request, *args, **kwargs)
def check(rule, ctxt, target={}, do_raise=True, exc=exceptions.HTTPForbidden): creds = ctxt.to_dict() try: result = _ENFORCER.enforce(rule, target, creds, do_raise, exc) except Exception: result = False raise else: return result finally: extra = {'policy': {'rule': rule, 'target': target}} if result: LOG.info(_("Policy check succeeded for rule " "'%(rule)s' on target %(target)s"), { 'rule': rule, 'target': repr(target) }, extra=extra) else: LOG.info(_("Policy check failed for rule " "'%(rule)s' on target: %(target)s"), { 'rule': rule, 'target': repr(target) }, extra=extra)
def update(self, request, env_template_id, body): """It updates the description template :param request: the operation request. :param env_template_id: the env template ID. :param body: the description to be updated :return: the updated template description. """ LOG.debug('Templates:Update <Id: {templ_id}, ' 'Body: {body}>'.format(templ_id=env_template_id, body=body)) target = {"env_template_id": env_template_id} policy.check('update_env_template', request.context, target) self._validate_request(request, env_template_id) try: LOG.debug('ENV TEMP NAME: {temp_name}>'.format( temp_name=body['name'])) if not str(body['name']).strip(): msg = _('Environment Template must contain at least one ' 'non-white space symbol') LOG.exception(msg) raise exc.HTTPBadRequest(msg) except Exception: msg = _('EnvTemplate body is incorrect') LOG.exception(msg) raise exc.HTTPBadRequest(msg) template = env_temps.EnvTemplateServices.update(env_template_id, body) return template.to_dict()
def show(self, request, environment_id, session_id): LOG.debug('Session:Show <SessionId: {id}>'.format(id=session_id)) unit = db_session.get_session() session = unit.query(models.Session).get(session_id) check_session(request, environment_id, session, session_id) user_id = request.context.user if session.user_id != user_id: msg = _('User <UserId {usr_id}> is not authorized to access' 'session <SessionId {s_id}>.').format(usr_id=user_id, s_id=session_id) LOG.error(msg) raise exc.HTTPUnauthorized(explanation=msg) if not sessions.SessionServices.validate(session): msg = _('Session <SessionId {0}> is invalid: environment has been' ' updated or updating right now with other session' ).format(session_id) LOG.error(msg) raise exc.HTTPForbidden(explanation=msg) return session.to_dict()
def __call__(self, request): """WSGI method that controls (de)serialization and method dispatch.""" LOG.debug("{method} {url}\nHEADERS: {headers}".format( method=request.method, url=request.url, headers=self._format_request_headers(request.headers))) try: action, action_args, accept = self.deserialize_request(request) except exceptions.UnsupportedContentType: msg = _("Unsupported Content-Type") return webob.exc.HTTPUnsupportedMediaType(detail=msg) except exceptions.NotAcceptableContentType: msg = _("Acceptable response can not be provided") return webob.exc.HTTPNotAcceptable(detail=msg) except exceptions.MalformedRequestBody: msg = _("Malformed request body") return webob.exc.HTTPBadRequest(explanation=msg) with ResourceExceptionHandler(): action_result = self.execute_action(action, request, **action_args) try: return self.serialize_response(action, action_result, accept) # return unserializable result (typically a webob exc) except Exception: return action_result
def delete(self, request, environment_id, session_id): LOG.debug('Session:Delete <SessionId: {0}>'.format(session_id)) unit = db_session.get_session() session = unit.query(models.Session).get(session_id) self._check_session(request, environment_id, session, session_id) user_id = request.context.user if session.user_id != user_id: msg = _('User <UserId {0}> is not authorized to access session' '<SessionId {1}>.').format(user_id, session_id) LOG.error(msg) raise exc.HTTPUnauthorized(explanation=msg) if session.state == states.SessionState.DEPLOYING: msg = _('Session <SessionId: {0}> is in deploying state and ' 'could not be deleted').format(session_id) LOG.error(msg) raise exc.HTTPForbidden(explanation=msg) with unit.begin(): unit.delete(session) return None
def update(self, request, env_template_id, body): """It updates the description template. :param request: the operation request. :param env_template_id: the env template ID. :param body: the description to be updated :return: the updated template description. """ LOG.debug('Templates:Update <Id: {templ_id}, ' 'Body: {body}>'.format(templ_id=env_template_id, body=body)) target = {"env_template_id": env_template_id} policy.check('update_env_template', request.context, target) self._validate_request(request, env_template_id) try: LOG.debug('ENV TEMP NAME: {temp_name}>'.format( temp_name=body['name'])) if not envs_api.VALID_NAME_REGEX.match(str(body['name'])): msg = _('Env Template must contain only alphanumeric ' 'or "_-." characters, must start with alpha') LOG.exception(msg) raise exc.HTTPBadRequest(msg) except Exception: msg = _('EnvTemplate body is incorrect') LOG.exception(msg) raise exc.HTTPBadRequest(msg) template = env_temps.EnvTemplateServices.update(env_template_id, body) return template.to_dict()
def update(self, request, env_template_id, body): """It updates the description template :param request: the operation request. :param env_template_id: the env template ID. :param body: the description to be updated :return: the updated template description. """ LOG.debug('Templates:Update <Id: {templ_id}, ' 'Body: {body}>'.format(templ_id=env_template_id, body=body)) target = {"env_template_id": env_template_id} policy.check('update_env_template', request.context, target) self._validate_request(request, env_template_id) try: LOG.debug( 'ENV TEMP NAME: {temp_name}>'.format(temp_name=body['name'])) if not str(body['name']).strip(): msg = _('Environment Template must contain at least one ' 'non-white space symbol') LOG.exception(msg) raise exc.HTTPBadRequest(msg) except Exception: msg = _('EnvTemplate body is incorrect') LOG.exception(msg) raise exc.HTTPBadRequest(msg) template = env_temps.EnvTemplateServices.update(env_template_id, body) return template.to_dict()
def update(self, request, env_template_id, body): """It updates the description template. :param request: the operation request. :param env_template_id: the env template ID. :param body: the description to be updated :return: the updated template description. """ LOG.debug('Templates:Update <Id: {templ_id}, ' 'Body: {body}>'.format(templ_id=env_template_id, body=body)) target = {"env_template_id": env_template_id} policy.check('update_env_template', request.context, target) self._validate_request(request, env_template_id) try: LOG.debug( 'ENV TEMP NAME: {temp_name}>'.format(temp_name=body['name'])) if not envs_api.VALID_NAME_REGEX.match(str(body['name'])): msg = _('Env Template must contain only alphanumeric ' 'or "_-." characters, must start with alpha') LOG.exception(msg) raise exc.HTTPBadRequest(msg) except Exception: msg = _('EnvTemplate body is incorrect') LOG.exception(msg) raise exc.HTTPBadRequest(msg) template = env_temps.EnvTemplateServices.update(env_template_id, body) return template.to_dict()
def upload(self, req, body=None): """Upload new file archive for the new package together with package metadata. """ policy.check("upload_package", req.context) _check_content_type(req, 'multipart/form-data') file_obj, package_meta = _validate_body(body) if package_meta: try: jsonschema.validate(package_meta, schemas.PKG_UPLOAD_SCHEMA) except jsonschema.ValidationError as e: msg = _("Package schema is not valid: {reason}").format( reason=e) LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) else: package_meta = {} if package_meta.get('is_public'): policy.check('publicize_package', req.context) with tempfile.NamedTemporaryFile(delete=False) as tempf: LOG.debug("Storing package archive in a temporary file") content = file_obj.file.read() if not content: msg = _("Uploading file can't be empty") LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) tempf.write(content) package_meta['archive'] = content try: with load_utils.load_from_file( tempf.name, target_dir=None, drop_dir=True) as pkg_to_upload: # extend dictionary for update db for k, v in six.iteritems(PKG_PARAMS_MAP): if hasattr(pkg_to_upload, k): package_meta[v] = getattr(pkg_to_upload, k) if len(package_meta['name']) > 80: msg = _('Package name should be 80 characters maximum') LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) try: package = db_api.package_upload( package_meta, req.context.tenant) except db_exc.DBDuplicateEntry: msg = _('Package with specified full ' 'name is already registered') LOG.exception(msg) raise exc.HTTPConflict(msg) return package.to_dict() except pkg_exc.PackageLoadError as e: msg = _("Couldn't load package from file: {reason}").format( reason=e) LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) finally: LOG.debug("Deleting package archive temporary file") os.remove(tempf.name)
def update(self, request, environment_id, body): """"Rename an environment.""" LOG.debug('Environments:Update <Id: {id}, ' 'Body: {body}>'.format(id=environment_id, body=body)) target = {"environment_id": environment_id} policy.check('update_environment', request.context, target) session = db_session.get_session() environment = session.query(models.Environment).get(environment_id) new_name = six.text_type(body['name']) if new_name.strip(): if len(new_name) > 255: msg = _('Environment name should be 255 characters maximum') LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) try: environment.update({'name': new_name}) environment.save(session) except db_exc.DBDuplicateEntry: msg = _('Environment with specified name already exists') LOG.error(msg) raise exc.HTTPConflict(explanation=msg) else: msg = _('Environment name must contain at least one ' 'non-white space symbol') LOG.error(msg) raise exc.HTTPClientError(explanation=msg) return environment.to_dict()
def _load_package(self, pkg_loader, name): try: parts = name.rsplit('/') if len(parts) == 2: name, pkg_version = parts version_spec = helpers.parse_version_spec(pkg_version) else: version_spec = helpers.parse_version_spec('*') package = pkg_loader.load_package(name, version_spec) except exceptions.NoPackageFound: if not CONF.engine.load_packages_from: msg = _('Local package is not found since "load-packages-from"' ' engine parameter is not provided and specified ' 'packages is not loaded to murano-api') else: msg = _('Specified package is not found: {0} were scanned ' 'together with murano database').format(','.join( CONF.engine.load_packages_from)) LOG.error(msg) self.error(msg, show_help=False) except exc.CommunicationError: msg = ('Murano API is not running. ' 'Check configuration parameters.') LOG.error(msg) self.error(msg, show_help=False) return package
def update(self, request, environment_id, body): LOG.debug('Environments:Update <Id: {id}, ' 'Body: {body}>'.format(id=environment_id, body=body)) target = {"environment_id": environment_id} policy.check('update_environment', request.context, target) session = db_session.get_session() environment = session.query(models.Environment).get(environment_id) new_name = six.text_type(body['name']) if new_name.strip(): if len(new_name) > 255: msg = _('Environment name should be 255 characters maximum') LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) try: environment.update(body) environment.save(session) except db_exc.DBDuplicateEntry: msg = _('Environment with specified name already exists') LOG.error(msg) raise exc.HTTPConflict(explanation=msg) else: msg = _('Environment name must contain at least one ' 'non-white space symbol') LOG.error(msg) raise exc.HTTPClientError(explanation=msg) return environment.to_dict()
def _load_image(self, file_name, default_name, what_image): full_path = path.secure_join(self._source_directory, file_name or default_name) if not os.path.isfile(full_path) and not file_name: return allowed_ftype = ('png', 'jpeg', 'gif') allowed_size = 500 * 1024 try: if imghdr.what(full_path) not in allowed_ftype: msg = _('{0}: Unsupported Format. Only {1} allowed').format( what_image, ', '.join(allowed_ftype)) raise exceptions.PackageLoadError(msg) fsize = os.stat(full_path).st_size if fsize > allowed_size: msg = _('{0}: Uploaded image size {1} is too large. ' 'Max allowed size is {2}').format( what_image, fsize, allowed_size) raise exceptions.PackageLoadError(msg) with open(full_path, 'rb') as stream: return stream.read() except Exception as ex: trace = sys.exc_info()[2] utils.reraise( exceptions.PackageLoadError, exceptions.PackageLoadError('Unable to load {0}: {1}'.format( what_image, ex)), trace)
def create(self, request, body): LOG.debug("Environments:Create <Body {body}>".format(body=body)) policy.check("create_environment", request.context) if not body.get("name"): msg = _("Please, specify a name of the environment to create") LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) name = unicode(body["name"]) if len(name) > 255: msg = _("Environment name should be 255 characters maximum") LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) if VALID_NAME_REGEX.match(name): try: environment = envs.EnvironmentServices.create(body.copy(), request.context) except db_exc.DBDuplicateEntry: msg = _("Environment with specified name already exists") LOG.exception(msg) raise exc.HTTPConflict(explanation=msg) else: msg = _('Environment name must contain only alphanumeric or "_-." ' "characters, must start with alpha") LOG.exception(msg) raise exc.HTTPClientError(explanation=msg) return environment.to_dict()
def show(self, request, environment_id, session_id): LOG.debug('Session:Show <SessionId: {id}>'.format(id=session_id)) unit = db_session.get_session() session = unit.query(models.Session).get(session_id) check_session(request, environment_id, session, session_id) user_id = request.context.user if session.user_id != user_id: msg = _('User <UserId {usr_id}> is not authorized to access ' 'session <SessionId {s_id}>.').format(usr_id=user_id, s_id=session_id) LOG.error(msg) raise exc.HTTPUnauthorized(explanation=msg) if not sessions.SessionServices.validate(session): msg = _('Session <SessionId {0}> is invalid: environment has been ' 'updated or updating right now with other session').format( session_id) LOG.error(msg) raise exc.HTTPForbidden(explanation=msg) return session.to_dict()
def create(self, request, body): """It creates the env template from the payload obtaining. This payload can contain just the template name, or include also service information. :param request: the operation request. :param body: the env template description :return: the description of the created template. """ LOG.debug('EnvTemplates:Create <Body {body}>'.format(body=body)) policy.check('create_env_template', request.context) try: LOG.debug('ENV TEMP NAME: {templ_name}>'.format( templ_name=body['name'])) if not envs_api.VALID_NAME_REGEX.match(str(body['name'])): msg = _('Environment Template must contain only alphanumeric ' 'or "_-." characters, must start with alpha') LOG.error(msg) raise exc.HTTPBadRequest(msg) except Exception: msg = _('Env template body is incorrect') LOG.exception(msg) raise exc.HTTPClientError(msg) if len(body['name']) > 255: msg = _('Environment Template name should be 255 characters ' 'maximum') LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) try: template = env_temps.EnvTemplateServices.create( body.copy(), request.context.tenant) return template.to_dict() except db_exc.DBDuplicateEntry: msg = _('Env Template with specified name already exists') LOG.exception(msg) raise exc.HTTPConflict(msg)
def _load_image(self, file_name, default_name, what_image): full_path = os.path.join( self._source_directory, file_name or default_name) if not os.path.isfile(full_path) and not file_name: return allowed_ftype = ('png', 'jpeg', 'gif') allowed_size = 500 * 1024 try: if imghdr.what(full_path) not in allowed_ftype: msg = _('{0}: Unsupported Format. Only {1} allowed').format( what_image, ', '.join(allowed_ftype)) raise exceptions.PackageLoadError(msg) fsize = os.stat(full_path).st_size if fsize > allowed_size: msg = _('{0}: Uploaded image size {1} is too large. ' 'Max allowed size is {2}').format( what_image, fsize, allowed_size) raise exceptions.PackageLoadError(msg) with open(full_path, 'rb') as stream: return stream.read() except Exception as ex: trace = sys.exc_info()[2] six.reraise(exceptions.PackageLoadError, exceptions.PackageLoadError( 'Unable to load {0}: {1}'.format(what_image, ex)), trace)
def delete(self, request, environment_id, session_id): LOG.debug('Session:Delete <SessionId: {s_id}>'.format(s_id=session_id)) unit = db_session.get_session() session = unit.query(models.Session).get(session_id) check_session(request, environment_id, session, session_id) user_id = request.context.user if session.user_id != user_id: msg = _('User <UserId {usr_id}> is not authorized to access ' 'session <SessionId {s_id}>.').format(usr_id=user_id, s_id=session_id) LOG.error(msg) raise exc.HTTPUnauthorized(explanation=msg) if session.state == states.SessionState.DEPLOYING: msg = _('Session <SessionId: {s_id}> is in deploying state ' 'and could not be deleted').format(s_id=session_id) LOG.error(msg) raise exc.HTTPForbidden(explanation=msg) with unit.begin(): unit.delete(session) return None
def _from_json_patch(self, datastring): try: operations = jsonutils.loads(datastring) except ValueError: msg = _("cannot understand JSON") raise exceptions.MalformedRequestBody(reason=msg) if not isinstance(operations, list): msg = _('JSON-patch must be a list.') raise webob.exc.HTTPBadRequest(explanation=msg) changes = [] for raw_change in operations: if not isinstance(raw_change, dict): msg = _('Operations must be JSON objects.') raise webob.exc.HTTPBadRequest(explanation=msg) (op, path) = self._parse_json_schema_change(raw_change) self._validate_path(path) change = {'op': op, 'path': path} change['value'] = self._get_change_value(raw_change, op) self._validate_change(change) changes.append(change) return changes
def _load_package(self, pkg_loader, name): try: parts = name.rsplit('/') if len(parts) == 2: name, pkg_version = parts version_spec = helpers.parse_version_spec(pkg_version) else: version_spec = helpers.parse_version_spec('*') package = pkg_loader.load_package(name, version_spec) except exceptions.NoPackageFound: if not CONF.packages_opts.load_packages_from: msg = _('Local package is not found since "load-packages-from"' ' engine parameter is not provided and specified ' 'packages is not loaded to murano-api') else: msg = _('Specified package is not found: {0} were scanned ' 'together with murano database' ).format(','.join( CONF.packages_opts.load_packages_from)) LOG.error(msg) self.error(msg, show_help=False) except exc.CommunicationError: msg = ('Murano API is not running. ' 'Check configuration parameters.') LOG.error(msg) self.error(msg, show_help=False) return package
def _get_category_filters(req): query_params = {} valid_query_params = ['sort_keys', 'sort_dir', 'limit', 'marker'] for key, value in req.GET.items(): if key not in valid_query_params: raise exc.HTTPBadRequest( _('Bad value passed to filter. ' 'Got {key}, exected:{valid}').format( key=key, valid=', '.join(valid_query_params))) if key == 'sort_keys': available_sort_keys = ['name', 'created', 'updated', 'package_count', 'id'] value = [v.strip() for v in value.split(',')] for sort_key in value: if sort_key not in available_sort_keys: raise exc.HTTPBadRequest( explanation=_('Invalid sort key: {sort_key}. ' 'Must be one of the following: ' '{available}').format( sort_key=sort_key, available=', '.join(available_sort_keys))) if key == 'sort_dir': if value not in ['asc', 'desc']: msg = _('Invalid sort direction: {0}').format(value) raise exc.HTTPBadRequest(explanation=msg) query_params[key] = value return query_params
def _validate_change(self, change): change_path = change['path'][0] change_op = change['op'] allowed_methods = self.allowed_operations.get(change_path) if not allowed_methods: msg = _("Attribute '{0}' is invalid").format(change_path) raise webob.exc.HTTPForbidden(explanation=six.text_type(msg)) if change_op not in allowed_methods: msg = _("Method '{method}' is not allowed for a path with name " "'{name}'. Allowed operations are: " "'{ops}'").format(method=change_op, name=change_path, ops=', '.join(allowed_methods)) raise webob.exc.HTTPForbidden(explanation=six.text_type(msg)) property_to_update = {change_path: change['value']} try: jsonschema.validate(property_to_update, schemas.PKG_UPDATE_SCHEMA) except jsonschema.ValidationError as e: LOG.error( _LE("Schema validation error occured: {error}").format( error=e)) raise webob.exc.HTTPBadRequest(explanation=e.message)
def clone(self, request, env_template_id, body): """Clones env template from another tenant It clones the env template from another env template from other tenant. :param request: the operation request. :param env_template_id: the env template ID. :param body: the request body. :return: the description of the created template. """ LOG.debug('EnvTemplates:Clone <Env Template {1} for body {0}>'. format(body, env_template_id)) policy.check('clone_env_template', request.context) old_env_template = self._validate_exists(env_template_id) if not old_env_template.get('is_public'): msg = _('User has no access to these resources.') LOG.error(msg) raise exc.HTTPForbidden(explanation=msg) self._validate_body_name(body) LOG.debug('ENV TEMP NAME: {0}'.format(body['name'])) try: is_public = body.get('is_public', False) template = env_temps.EnvTemplateServices.clone( env_template_id, request.context.tenant, body['name'], is_public) except db_exc.DBDuplicateEntry: msg = _('Env template with specified name already exists') LOG.error(msg) raise exc.HTTPConflict(explanation=msg) return template.to_dict()
def run_tests(args): provided_pkg_name = args.package load_packages_from = args.load_packages_from tests_to_run = args.tests if not provided_pkg_name: msg = _('Package name is required parameter.') sys.stderr.write("ERROR: {msg}".format(msg=msg)) sys.exit(1) ks_opts = _validate_keystone_opts(args) client = ks_client.Client(**ks_opts) test_env = environment.Environment() test_env.token = client.auth_token test_env.tenant_id = client.auth_tenant_id test_env.clients = client_manager.ClientManager(test_env) murano_client_factory = lambda: \ test_env.clients.get_murano_client(test_env) # Replace location of loading packages with provided from command line. if load_packages_from: cfg.CONF.engine.load_packages_from = load_packages_from with package_loader.CombinedPackageLoader( murano_client_factory, client.tenant_id) as pkg_loader: engine.get_plugin_loader().register_in_loader(pkg_loader) exc = executor.MuranoDslExecutor( pkg_loader, engine.ContextManager(), test_env) package = _load_package(pkg_loader, provided_pkg_name) class_to_methods, class_to_obj = _get_all_test_methods(exc, package) run_set = _get_methods_to_run(package, tests_to_run, class_to_methods) if run_set: LOG.debug('Starting test execution.') else: msg = _('No tests found for execution.') LOG.error(msg) sys.stderr.write("ERROR: {msg}".format(msg=msg)) sys.exit(1) for pkg_class, methods in run_set.iteritems(): obj = class_to_obj[pkg_class] for m in methods: _call_service_method('setUp', exc, obj) obj.type.methods[m].usage = 'Action' test_env.start() try: obj.type.invoke(m, exc, obj, (), {}) LOG.debug('\n.....{0}.{1}.....OK'.format(obj.type.name, m)) _call_service_method('tearDown', exc, obj) except Exception: LOG.exception('\n.....{0}.{1}.....FAILURE\n' ''.format(obj.type.name, m)) finally: test_env.finish()
def run_tests(args): provided_pkg_name = args.package load_packages_from = args.load_packages_from tests_to_run = args.tests if not provided_pkg_name: msg = _('Package name is required parameter.') sys.stderr.write("ERROR: {msg}".format(msg=msg)) sys.exit(1) ks_opts = _validate_keystone_opts(args) client = ks_client.Client(**ks_opts) test_env = environment.Environment() test_env.token = client.auth_token test_env.tenant_id = client.auth_tenant_id test_env.clients = client_manager.ClientManager(test_env) murano_client_factory = lambda: \ test_env.clients.get_murano_client(test_env) # Replace location of loading packages with provided from command line. if load_packages_from: cfg.CONF.engine.load_packages_from = load_packages_from with package_loader.CombinedPackageLoader(murano_client_factory, client.tenant_id) as pkg_loader: engine.get_plugin_loader().register_in_loader(pkg_loader) exc = executor.MuranoDslExecutor(pkg_loader, engine.ContextManager(), test_env) package = _load_package(pkg_loader, provided_pkg_name) class_to_methods, class_to_obj = _get_all_test_methods(exc, package) run_set = _get_methods_to_run(package, tests_to_run, class_to_methods) if run_set: LOG.debug('Starting test execution.') else: msg = _('No tests found for execution.') LOG.error(msg) sys.stderr.write("ERROR: {msg}".format(msg=msg)) sys.exit(1) for pkg_class, methods in run_set.iteritems(): obj = class_to_obj[pkg_class] for m in methods: _call_service_method('setUp', exc, obj) obj.type.methods[m].usage = 'Action' test_env.start() try: obj.type.invoke(m, exc, obj, (), {}) LOG.debug('\n.....{0}.{1}.....OK'.format(obj.type.name, m)) _call_service_method('tearDown', exc, obj) except Exception: LOG.exception('\n.....{0}.{1}.....FAILURE\n' ''.format(obj.type.name, m)) finally: test_env.finish()
def validate(self, model, class_loader=None): """Validate model using Congress rule engine. @type model: dict @param model: Dictionary representation of model starting on environment level (['Objects']) @type class_loader: murano.dsl.class_loader.MuranoClassLoader @param class_loader: Optional. Used for evaluating parent class types @raises ValidationError in case validation was not successful """ if model is None: return client = self._client_manager.get_congress_client(self._environment) if not client: raise ValueError(_('Congress client is not configured!')) LOG.info(_LI('Validating model')) LOG.debug(model) rules = congress_rules.CongressRulesManager().convert( model, class_loader, self._environment.tenant_id) rules_str = map(str, rules) env_id = model['?']['id'] # cleanup of data populated by murano driver rules_str.insert(0, 'deleteEnv("{0}")'.format(env_id)) rules_line = " ".join(rules_str) LOG.debug('Congress rules: \n ' + '\n '.join(rules_str)) validation_result = client.execute_policy_action( "murano_system", "simulate", False, False, {'query': 'predeploy_errors(eid, oid, msg)', 'action_policy': 'murano_action', 'sequence': rules_line}) if validation_result["result"]: messages = self._parse_messages(env_id, validation_result["result"]) if messages: result_str = "\n ".join(map(str, messages)) msg = _("Murano object model validation failed: {0}").format( "\n " + result_str) LOG.error(msg) raise ValidationError(msg) else: LOG.info(_LI('Model valid'))
def _authorize_package(package, context, allow_public=False): if package.owner_id != context.tenant: if not allow_public: msg = _("Package '{0}' is not owned by " "tenant '{1}'").format(package.id, context.tenant) LOG.error(msg) raise exc.HTTPForbidden(explanation=msg) if not package.is_public: msg = _("Package '{0}' is not public and not owned by " "tenant '{1}' ").format(package.id, context.tenant) LOG.error(msg) raise exc.HTTPForbidden(explanation=msg)
def _validate_request(self, request, env_template_id): env_template_exists = env_temps.EnvTemplateServices.env_template_exist if not env_template_exists(env_template_id): mng = _("EnvTemplate <TempId {0}> is not found").format(env_template_id) LOG.exception(mng) raise exc.HTTPNotFound(explanation=mng) get_env_template = env_temps.EnvTemplateServices.get_env_template env_template = get_env_template(env_template_id) if env_template.tenant_id != request.context.tenant: LOG.exception(_("User is not authorized to access " "this tenant resources.")) raise exc.HTTPUnauthorized
def validate(self, model, class_loader=None): """Validate model using Congress rule engine. @type model: dict @param model: Dictionary representation of model starting on environment level (['Objects']) @type class_loader: murano.dsl.class_loader.MuranoClassLoader @param class_loader: Optional. Used for evaluating parent class types @raises ValidationError in case validation was not successful """ if model is None: return client = self._client_manager.get_congress_client(self._environment) if not client: raise ValueError(_('Congress client is not configured!')) LOG.info(_LI('Validating model')) LOG.debug(model) rules = congress_rules.CongressRulesManager().convert( model, class_loader, self._environment.tenant_id) rules_str = map(str, rules) env_id = model['?']['id'] # cleanup of data populated by murano driver rules_str.insert(0, 'deleteEnv("{0}")'.format(env_id)) rules_line = " ".join(rules_str) LOG.debug('Congress rules: \n ' + '\n '.join(rules_str)) validation_result = client.execute_policy_action( "murano_system", "simulate", False, False, { 'query': 'predeploy_errors(eid, oid, msg)', 'action_policy': 'murano_action', 'sequence': rules_line }) if validation_result["result"]: messages = self._parse_messages(env_id, validation_result["result"]) if messages: result_str = "\n ".join(map(str, messages)) msg = _("Murano object model validation failed: {0}").format( "\n " + result_str) LOG.error(msg) raise ValidationError(msg) else: LOG.info(_LI('Model valid'))
def _validate_request(self, request, env_template_id): env_template_exists = env_temps.EnvTemplateServices.env_template_exist if not env_template_exists(env_template_id): msg = _('EnvTemplate <TempId {temp_id}> is not found').format( temp_id=env_template_id) LOG.exception(msg) raise exc.HTTPNotFound(explanation=msg) get_env_template = env_temps.EnvTemplateServices.get_env_template env_template = get_env_template(env_template_id) if env_template.tenant_id != request.context.tenant: msg = _('User is not authorized to access this tenant resources') LOG.error(msg) raise exc.HTTPForbidden(explanation=msg)
def _validate_body_name(self, body): if not('name' in body and body['name'].strip()): msg = _('Please, specify a name of the environment template.') LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) name = six.text_type(body['name']) if len(name) > 255: msg = _('Environment template name should be 255 characters ' 'maximum') LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg)
def _validate_body_name(self, body): if not ('name' in body and body['name'].strip()): msg = _('Please, specify a name of the environment template.') LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) name = str(body['name']) if len(name) > 255: msg = _('Environment template name should be 255 characters ' 'maximum') LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg)
def _check_session(self, request, environment_id, session, session_id): if session is None: msg = _('Session <SessionId {0}> is not found').format(session_id) LOG.error(msg) raise exc.HTTPNotFound(explanation=msg) if session.environment_id != environment_id: msg = _('Session <SessionId {0}> is not tied with Environment ' '<EnvId {1}>').format(session_id, environment_id) LOG.error(msg) raise exc.HTTPNotFound(explanation=msg) self._check_environment(request, environment_id)
def _validate_request(self, request, env_template_id): env_template_exists = env_temps.EnvTemplateServices.env_template_exist if not env_template_exists(env_template_id): mng = _('EnvTemplate <TempId {0}> is not found').format( env_template_id) LOG.exception(mng) raise exc.HTTPNotFound(explanation=mng) get_env_template = env_temps.EnvTemplateServices.get_env_template env_template = get_env_template(env_template_id) if env_template.tenant_id != request.context.tenant: LOG.exception(_('User is not authorized to access ' 'this tenant resources.')) raise exc.HTTPUnauthorized
def _check_environment(self, request, environment_id): unit = db_session.get_session() environment = unit.query(models.Environment).get(environment_id) if environment is None: msg = _("Environment <EnvId {0}>" " is not found").format(environment_id) LOG.error(msg) raise exc.HTTPNotFound(explanation=msg) if environment.tenant_id != request.context.tenant: msg = _("User is not authorized to access " "this tenant resources.") LOG.error(msg) raise exc.HTTPUnauthorized(explanation=msg)
def check_env(request, environment_id): unit = db_session.get_session() environment = unit.query(models.Environment).get(environment_id) if environment is None: msg = _('Environment with id {0}' ' not found').format(environment_id) LOG.warning(msg) raise exc.HTTPNotFound(explanation=msg) if hasattr(request, 'context'): if environment.tenant_id != request.context.tenant: msg = _('User is not authorized to access' ' these tenant resources') LOG.warning(msg) raise exc.HTTPForbidden(explanation=msg)
def create_environment(self, request, env_template_id, body): """Creates environment and session from template. :param request: operation request :param env_template_id: environment template ID :param body: the environment name :return: session_id and environment_id """ LOG.debug('Templates:Create environment <Id: {templ_id}>'. format(templ_id=env_template_id)) target = {"env_template_id": env_template_id} policy.check('create_environment', request.context, target) self._validate_request(request, env_template_id) template = env_temps.EnvTemplateServices.\ get_env_template(env_template_id) if ('name' not in body or not envs_api.VALID_NAME_REGEX.match(str(body['name']))): msg = _('Environment must contain only alphanumeric ' 'or "_-." characters, must start with alpha') LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) LOG.debug('ENVIRONMENT NAME: {env_name}>'.format( env_name=body['name'])) try: environment = envs.EnvironmentServices.create( body.copy(), request.context) except db_exc.DBDuplicateEntry: msg = _('Environment with specified name already exists') LOG.exception(msg) raise exc.HTTPConflict(explanation=msg) user_id = request.context.user session = sessions.SessionServices.create(environment.id, user_id) if self.has_services(template): services_node = utils.TraverseHelper.get("services", template.description) utils.TraverseHelper.update("/Objects/services", services_node, environment.description) envs.EnvironmentServices.save_environment_description( session.id, environment.description, inner=False ) return {"session_id": session.id, "environment_id": environment.id}
def _check_environment(self, request, environment_id): unit = db_session.get_session() environment = unit.query(models.Environment).get(environment_id) if environment is None: msg = _('Environment <EnvId {0}>' ' is not found').format(environment_id) LOG.error(msg) raise exc.HTTPNotFound(explanation=msg) if environment.tenant_id != request.context.tenant: msg = _('User is not authorized to access ' 'this tenant resources.') LOG.error(msg) raise exc.HTTPUnauthorized(explanation=msg)
def check_session(request, environment_id, session, session_id): """Validate, that a session is ok.""" if session is None: msg = _('Session <SessionId {id}> is not found').format(id=session_id) LOG.error(msg) raise exc.HTTPNotFound(explanation=msg) if session.environment_id != environment_id: msg = _('Session <SessionId {session_id}> is not tied ' 'with Environment <EnvId {environment_id}>').format( session_id=session_id, environment_id=environment_id) LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) check_env(request, environment_id)
def post_env_template_data(env_template_id, data, path): """It stores the template data inside the template description. :param env_template_id: The env_template_id to obtain the data :param data: the template description :param path: Id of service for which we checking status. :return: The template description """ get_description = env_temp.EnvTemplateServices.get_description save_description = env_temp.EnvTemplateServices.save_description temp_description = get_description(env_template_id) if temp_description is None: msg = _('Environment Template <EnvId {id}> is not found').format( id=env_template_id) LOG.error(msg) raise exc.HTTPNotFound(explanation=msg) if 'services' not in temp_description: temp_description['services'] = [] if path == '/services': if isinstance(data, list): utils.TraverseHelper.extend(path, data, temp_description) else: utils.TraverseHelper.insert(path, data, temp_description) save_description(temp_description) return data
def get_template_data(env_template_id, path): """It obtains the data for the template. It includes all the services. In case the path includes information such as the env_template_id, the information provided will be related to the entity specified in the path :param env_template_id: The env_template_id to obtain the data :param path: Id of service for which we checking status. :return: The template description """ temp_description = env_temp.EnvTemplateServices.\ get_description(env_template_id) if temp_description is None: return None if 'services' not in temp_description: return [] result = utils.TraverseHelper.get(path, temp_description) if result is None: msg = _('Environment Template <EnvId {id}> is not found').format( id=env_template_id) LOG.error(msg) raise exc.HTTPNotFound(explanation=msg) return result
def put(self, request, env_template_id, path, body): """It updates a service into a template. :param request: The operation request. :param env_template_id: the env template ID where the service belongs to. :param path: The path :param body: the information about the service :return: the service description updated. """ LOG.debug('Applications:Put <EnvTempId: {templ_id}, Path: {path}, ' 'Body: {body}>'.format(templ_id=env_template_id, body=body, path=path)) put_data = core_services.CoreServices.put_data session_id = request.context.session try: result = put_data(env_template_id, session_id, body, path) except (KeyError, ValueError): msg = _('The template does not exist {templ_id}').format( templ_id=env_template_id) LOG.exception(msg) raise exc.HTTPNotFound(msg) return result