예제 #1
0
    def post(self, data):
        """Create a new pipeline."""
        policy.check('create_pipeline', pecan.request)
        js_data = data.as_dict(objects.registry.Pipeline)
        host_url = pecan.request.application_url.rstrip('/')
        if data.plan_uri is not wsme.Unset:
            plan_uri = data.plan_uri
            if plan_uri.startswith(host_url):
                pl_uuid = plan_uri.split('/')[-1]
                pl = objects.registry.Plan.get_by_uuid(
                    pecan.request.security_context, pl_uuid)
                js_data['plan_id'] = pl.id
            else:
                # TODO(asalkeld) we are not hosting the plan so
                # download the plan and insert it into our db.
                raise exception.BadRequest(reason=_(
                    'The plan was not hosted in solum'))

        if js_data.get('plan_id') is None:
            raise exception.BadRequest(reason=_(
                'The plan was not given or could not be found'))

        handler = pipeline_handler.PipelineHandler(
            pecan.request.security_context)
        return pipeline.Pipeline.from_db_model(
            handler.create(js_data), host_url)
예제 #2
0
    def _update_app_scale_config(self, app, data):

        scale_config = dict()
        target = data.get('scale_target', '1')
        try:
            target = int(target)
        except ValueError:
            msg = "Must provide integer value for scale target."
            raise exception.BadRequest(reason=msg)

        if target <= 0:
            msg = "Scale target must be greater than zero."
            raise exception.BadRequest(reason=msg)

        if target > cfg.CONF.api.max_instances_per_app:
            msg = "Target scale '%s' exceeds maximum scale limit '%s'." % (
                target, cfg.CONF.api.max_instances_per_app)
            raise exception.ResourceLimitExceeded(reason=msg)

        current_config = app.scale_config

        if current_config:
            current_config[app.name]['target'] = str(target)
            scale_config['scale_config'] = current_config
        else:
            config_data = dict()
            config_data['target'] = str(target)
            app_scale_config = dict()
            app_scale_config[app.name] = config_data
            scale_config = dict()
            scale_config['scale_config'] = app_scale_config

        objects.registry.App.update_and_save(self.context, app.id,
                                             scale_config)
예제 #3
0
파일: app.py 프로젝트: paperandsoap/solum
    def post(self, data):
        """Create a new app."""
        request.check_request_for_https()
        if not data:
            raise exception.BadRequest(reason='No data.')

        self._validate(data)

        handler = app_handler.AppHandler(pecan.request.security_context)

        app_data = data.as_dict(app.App)

        try:
            raw_content = yamlutils.load(pecan.request.body)
        except ValueError:
            try:
                raw_content = json.loads(pecan.request.body)
            except ValueError as exp:
                LOG.exception(exp)
                raise exception.BadRequest(reason='Invalid app data.')

        app_data['raw_content'] = json.dumps(raw_content)

        new_app = handler.create(app_data)
        created_app = app.App.from_db_model(new_app, pecan.request.host_url)
        return created_app
예제 #4
0
    def patch(self, uuid):
        """Patch an existing CAMP-style plan."""

        handler = (plan_handler.
                   PlanHandler(pecan.request.security_context))
        plan_obj = handler.get(uuid)

        # TODO([email protected]) check if there are any assemblies that
        # refer to this plan and raise an PlanStillReferenced exception if
        # there are.

        if not pecan.request.body or len(pecan.request.body) < 1:
            raise exception.BadRequest(reason='empty request body')

        # check to make sure the request has the right Content-Type
        if (pecan.request.content_type is None or
                pecan.request.content_type != 'application/json-patch+json'):
            raise exception.UnsupportedMediaType(
                name=pecan.request.content_type,
                method='PATCH')

        try:
            patch = jsonpatch.JsonPatch.from_string(pecan.request.body)
            patched_obj = patch.apply(plan_obj.refined_content())
            db_obj = handler.update(uuid, patched_obj)
        except KeyError:
            # a key error indicates one of the patch operations is missing a
            # component
            raise exception.BadRequest(reason=MAL_PATCH_ERR)
        except jsonpatch.JsonPatchConflict:
            raise exception.Unprocessable
        except jsonpatch.JsonPatchException as jpe:
            raise JsonPatchProcessingException(reason=six.text_type(jpe))

        return fluff_plan(db_obj.refined_content(), db_obj.uuid)
예제 #5
0
파일: app.py 프로젝트: paperandsoap/solum
    def _validate(self, app_data):
        # check max apps created for given tenant
        handler = app_handler.AppHandler(pecan.request.security_context)
        if len(handler.get_all()) >= cfg.CONF.api.max_apps_per_tenant:
            msg = "Cannot create application as maximum allowed limit reached."
            raise exception.ResourceLimitExceeded(reason=msg)

        if not app_data.languagepack:
            raise exception.BadRequest(reason="Languagepack not specified.")

        if not app_data.name:
            raise exception.BadRequest(reason='App name cannot be empty.')

        msg = ("Application name must be 1-100 characters long, only contain "
               "a-z,0-9,-,_ and start with an alphabet character.")
        # check if app name contains any invalid characters
        if not app_data.name or not app_data.name[0].isalpha():
            raise exception.BadRequest(reason=msg)

        try:
            re.match(r'^([a-z0-9-_]{1,100})$', app_data.name).group(0)
        except AttributeError:
            raise exception.BadRequest(reason=msg)

        # check if languagepack exists or not
        if str(app_data.languagepack).lower() != "false":
            try:
                objects.registry.Image.get_lp_by_name_or_uuid(
                    pecan.request.security_context,
                    app_data.languagepack,
                    include_operators_lp=True)
            except exception.ResourceNotFound:
                raise exception.ObjectNotFound(name="Languagepack",
                                               id=app_data.languagepack)
예제 #6
0
def init_plan_by_version(yml_input_plan):
    version = yml_input_plan.get('version')
    if version is None:
        raise exception.BadRequest(
            reason='Version attribute is missing in Plan')
    mod = sys.modules[__name__]
    if not hasattr(mod, 'init_plan_v%s' % version):
        raise exception.BadRequest(reason='Plan version %s is invalid.' %
                                   version)
    return getattr(mod, 'init_plan_v%s' % version)(yml_input_plan)
예제 #7
0
파일: plan.py 프로젝트: maniacs-ops/solum
def init_plan_v1(yml_input_plan):
    if not yml_input_plan.get('name'):
        raise exception.BadRequest(reason="Name field is missing.")
    try:
        pp = plan.Plan(**yml_input_plan)
    except ValueError as ve:
        raise exception.BadRequest(reason=six.text_type(ve))
    try:
        name_regex = re.compile(r'^([a-zA-Z0-9-_]{1,100})$')
        assert name_regex.match(pp.name), 'Plan name is invalid.'
    except AssertionError as ae:
        raise exception.BadRequest(reason=six.text_type(ae))
    return pp
예제 #8
0
    def post(self, data):
        """Create a new workflow."""
        request.check_request_for_https()
        if not data:
            raise exception.BadRequest(reason='No data.')

        ahandler = app_handler.AppHandler(pecan.request.security_context)
        app_model = ahandler.get(self.app_id)

        handler = wf_handler.WorkflowHandler(pecan.request.security_context)

        data.app_id = app_model.id
        data.config = app_model.workflow_config
        data.source = app_model.source

        wf_data = data.as_dict(workflow.Workflow)

        du_id = None
        if data.du_id:
            du_id = data.du_id
            self._verify_du_exists(pecan.request.security_context, du_id)

        return workflow.Workflow.from_db_model(
            handler.create(wf_data, commit_sha='', status_url='', du_id=du_id),
            pecan.request.host_url)
예제 #9
0
    def put(self):
        """Modify this plan."""
        policy.check('update_plan',
                     pecan.request.security_context)
        # make sure the plan exists before parsing the request
        handler = plan_handler.PlanHandler(pecan.request.security_context)
        handler.get(self._id)

        host_url = pecan.request.application_url.rstrip('/')
        if not pecan.request.body or len(pecan.request.body) < 1:
            raise exception.BadRequest(reason="No data.")

        if (pecan.request.content_type is not None and
                'yaml' in pecan.request.content_type):
            data = init_yml_plan_by_version()
            updated_plan_yml = yamlutils.dump(yaml_content(handler.update(
                self._id, data.as_dict(objects.registry.Plan))))
        else:
            data = init_json_plan_by_version()
            plan_obj = handler.update(self._id,
                                      data.as_dict(objects.registry.Plan))
            updated_plan_yml = wsme_json.encode_result(plan.Plan.from_db_model(
                plan_obj, host_url), plan.Plan)

        pecan.response.status = 200
        return updated_plan_yml
예제 #10
0
파일: plan.py 프로젝트: maniacs-ops/solum
def init_json_plan_by_version():
    try:
        json_input_plan = json.loads(pecan.request.body)
    except ValueError as excp:
        raise exception.BadRequest(reason='Plan is invalid. '
                                          + six.text_type(excp))
    return init_plan_by_version(json_input_plan)
예제 #11
0
파일: plan.py 프로젝트: maniacs-ops/solum
def init_yml_plan_by_version():
    try:
        yml_input_plan = yamlutils.load(pecan.request.body)
    except ValueError as excp:
        LOG.error("Invalid plan.")
        raise exception.BadRequest(reason='Plan is invalid. '
                                          + six.text_type(excp))
    return init_plan_by_version(yml_input_plan)
예제 #12
0
def check_url(data):
    # try to use a correct git uri
    pt = re.compile(r'^(http://|https://|git@)(.+)(/|:/)(.+)(.+)(\.git)')
    match = pt.search(data)
    if not match:
        msg = ("Bad git url. Provide git url in the following format: \n"
               "Public repo: https://github.com/<USER>/<REPO>.git\n"
               "Private repo: <http://|git@><HOST>:<USER>/<REPO>.git\n")
        raise exc.BadRequest(reason=msg)
예제 #13
0
 def _verify_du_exists(self, ctxt, du_id):
     du_image_backend = cfg.CONF.worker.image_storage
     if du_image_backend.lower() == 'glance':
         self._verify_du_image_exists_in_glance(ctxt, du_id)
     elif du_image_backend.lower() == 'swift':
         self._verify_du_image_exists_in_swift(ctxt, du_id)
     else:
         raise exception.BadRequest(message="DU image id not recognized.")
     return
예제 #14
0
    def post(self, trigger_id):
        """Trigger a new event on Solum."""
        policy.check('create_trigger', pecan.request.security_context)
        commit_sha = ''
        status_url = None
        collab_url = None

        try:
            query = query_dict(pecan.request.query_string)
            workflow = self._get_workflow(query)

            body = json.loads(pecan.request.body)
            if ('sender' in body and 'url' in body['sender']
                    and 'api.github.com' in body['sender']['url']):
                action = body.get('action', None)
                if 'comment' in body:
                    # Process a request for rebuilding
                    commit_sha, collab_url = self._process_request(body)
                elif 'pull_request' in body:
                    # Process a GitHub pull request
                    commit_sha = body['pull_request']['head']['sha']
                else:
                    raise exception.NotImplemented()

                # An example of Github statuses_url
                # https://api.github.com/repos/:user/:repo/statuses/{sha}
                if commit_sha:
                    status_url = body['repository']['statuses_url'].format(
                        sha=commit_sha)
            else:
                # Request NOT from a Github repo
                raise exception.NotImplemented()
        except Exception as exc:
            if isinstance(exc, exception.SolumException):
                raise
            info_msg = "Expected fields not found in request body."
            LOG.info(info_msg)
            raise exception.BadRequest(reason=info_msg)

        try:
            # Trigger workflow only on PR create and on rebuild request
            if action in [
                    'created', 'opened', 'edited', 'reopened', 'synchronize',
                    'closed'
            ]:
                handler = app_handler.AppHandler(None)
                handler.trigger_workflow(trigger_id,
                                         commit_sha,
                                         status_url,
                                         collab_url,
                                         workflow=workflow)
        except exception.ResourceNotFound:
            LOG.error("Incorrect trigger url.")
            raise

        pecan.response.status = 202
예제 #15
0
 def test_wrap_under_500(self, mockpost, mockreq, mockresp):
     mockpost.__name__ = 'post'
     mockreq.__name__ = 'request'
     mockresp.__name__ = 'response'
     mockpost.side_effect = exception.BadRequest(reason="Testing")
     mockreq.body = '{"foo":"bar"}'
     mockreq.content_type = "application/json"
     resp = TestWsmePecanController().post()
     self.assertEqual(exception.BadRequest.code, mockresp.status)
     self.assertIn('Testing', resp.get('faultstring'))
예제 #16
0
    def post(self, data):
        """Create a new languagepack."""
        handler = language_pack_handler.LanguagePackHandler(
            pecan.request.security_context)
        host_url = pecan.request.host_url

        msg = ("Languagepack name must be 1-100 characters long, only contain "
               "a-z,0-9,-,_ and start with an alphabet character.")
        if not data.name or not data.name[0].isalpha():
            raise exception.BadRequest(reason=msg)

        try:
            re.match(r'^([a-z0-9-_]{1,100})$', data.name).group(0)
        except AttributeError:
            raise exception.BadRequest(reason=msg)

        return language_pack.LanguagePack.from_db_model(
            handler.create(data.as_dict(objects.registry.Image),
                           data.lp_metadata, data.lp_params), host_url)
예제 #17
0
    def _validate(self, app_data):
        # check max apps created for given tenant
        handler = app_handler.AppHandler(pecan.request.security_context)
        if len(handler.get_all()) >= cfg.CONF.api.max_apps_per_tenant:
            msg = "Cannot create application as maximum allowed limit reached."
            raise exception.ResourceLimitExceeded(reason=msg)

        if not app_data.languagepack:
            raise exception.BadRequest(reason="Languagepack not specified.")

        if not app_data.name:
            raise exception.BadRequest(reason='App name cannot be empty.')

        # check if languagepack exists or not
        try:
            objects.registry.Image.get_lp_by_name_or_uuid(
                pecan.request.security_context,
                app_data.languagepack,
                include_operators_lp=True)
        except exception.ResourceNotFound:
            raise exception.ObjectNotFound(name="Languagepack",
                                           id=app_data.languagepack)
예제 #18
0
 def post(self):
     """Create a new plan."""
     if not pecan.request.body or len(pecan.request.body) < 1:
         raise exception.BadRequest
     try:
         yml_input_plan = yamlutils.load(pecan.request.body)
     except ValueError as excp:
         raise exception.BadRequest(reason='Plan is invalid. ' +
                                    excp.message)
     handler, data = init_plan_by_version(yml_input_plan)
     create_plan_yml = yamlutils.dump(
         yaml_content(handler.create(data.as_dict(objects.registry.Plan))))
     pecan.response.status = 201
     return create_plan_yml
예제 #19
0
    def patch(self, data):
        """Modify this app."""
        request.check_request_for_https()
        handler = app_handler.AppHandler(pecan.request.security_context)
        handler.get(self._id)

        if not data:
            raise exception.BadRequest(reason="No body detected")

        updated_app = handler.patch(self._id, data)
        updated_app = app.App.from_db_model(updated_app,
                                            pecan.request.host_url)

        return updated_app
예제 #20
0
파일: assembly.py 프로젝트: paulczar/solum
    def post(self, data):
        """Create a new assembly."""
        js_data = data.as_dict(objects.registry.Assembly)
        if data.plan_uri is not wsme.Unset:
            plan_uri = data.plan_uri
            if plan_uri.startswith(pecan.request.host_url):
                pl_uuid = plan_uri.split('/')[-1]
                pl = objects.registry.Plan.get_by_uuid(
                    pecan.request.security_context, pl_uuid)
                js_data['plan_id'] = pl.id
            else:
                # TODO(asalkeld) we are not hosting the plan so
                # download the plan and insert it into our db.
                raise exception.BadRequest(
                    reason=_('The plan was not hosted in solum'))

        if js_data.get('plan_id') is None:
            raise exception.BadRequest(
                reason=_('The plan was not given or could not be found'))

        handler = assembly_handler.AssemblyHandler(
            pecan.request.security_context)
        return assembly.Assembly.from_db_model(handler.create(js_data),
                                               pecan.request.host_url)
예제 #21
0
    def post(self, data):
        """Create a new app."""
        request.check_request_for_https()
        if not data:
            raise exception.BadRequest(reason='No data.')

        self._validate(data)

        handler = app_handler.AppHandler(pecan.request.security_context)

        app_data = data.as_dict(app.App)

        new_app = handler.create(app_data)
        created_app = app.App.from_db_model(new_app, pecan.request.host_url)
        return created_app
예제 #22
0
    def create(self, data, commit_sha, status_url, du_id):
        """Create a new workflow."""

        db_obj = objects.registry.Workflow()
        db_obj.id = uuidutils.generate_uuid()
        db_obj.user_id = self.context.user
        db_obj.project_id = self.context.tenant
        db_obj.deleted = False

        db_obj.app_id = data['app_id']
        db_obj.source = data['source']
        db_obj.config = data['config']
        db_obj.actions = data['actions']

        now = datetime.datetime.utcnow()
        db_obj.created_at = now
        db_obj.updated_at = now

        app_obj = objects.registry.App.get_by_id(self.context, db_obj.app_id)

        if str(app_obj.languagepack).lower() == 'false' and not du_id:
            msg = ("App {app} registered without a languagepack and no "
                   "du id specified. Either register the app with"
                   " a languagepack, or if there is already a pre"
                   "built du for the app, specify its id with --du-id"
                   " command line flag.")
            msg = msg.format(app=app_obj.name)
            raise exception.BadRequest(reason=msg)

        self._update_app_scale_config(app_obj, data)

        plan, assem = PlanAssemblyAdapter(self.context, db_obj,
                                          app_obj).create_dummies()

        db_obj.assembly = assem.id

        workflow.Workflow.insert(self.context, db_obj)

        self._execute_workflow_actions(db_obj,
                                       app_obj,
                                       assem,
                                       commit_sha=commit_sha,
                                       status_url=status_url,
                                       du_id=du_id)

        # TODO(devkulkarni): Update status of actions

        return db_obj
예제 #23
0
파일: plan.py 프로젝트: maniacs-ops/solum
    def post(self):
        """Create a new plan."""
        if not pecan.request.body or len(pecan.request.body) < 1:
            raise exception.BadRequest(reason="No data.")

        handler = plan_handler.PlanHandler(pecan.request.security_context)

        if (pecan.request.content_type is not None and
                'yaml' in pecan.request.content_type):
            data = init_yml_plan_by_version()
            created_plan = yamlutils.dump(yaml_content(handler.create(
                data.as_dict(objects.registry.Plan))))
        else:
            data = init_json_plan_by_version()
            plan_wsme = plan.Plan.from_db_model(handler.create(
                data.as_dict(objects.registry.Plan)), pecan.request.host_url)
            created_plan = wsme_json.encode_result(plan_wsme, plan.Plan)

        pecan.response.status = 201
        return created_plan
예제 #24
0
    def post(self):
        """Create a new application.

        There are a number of ways to use this method to create a new
        application. See Section 6.11 of the CAMP v1.1 specification
        for an explanation of each. Use the Content-Type of request to
        determine what the client is trying to do.
        """
        if pecan.request.content_type is None:
            raise exception.UnsupportedMediaType(
                name=pecan.request.content_type, method='POST')

        req_content_type = pecan.request.content_type

        # deploying by reference uses a JSON payload
        if req_content_type == 'application/json':
            payload = pecan.request.body
            if not payload or len(payload) < 1:
                raise exception.BadRequest(reason='empty request body')

            try:
                json_ref_doc = json.loads(payload)
            except ValueError as excp:
                raise exception.BadRequest(reason='JSON object is invalid. ' +
                                           six.text_type(excp))

            if 'plan_uri' in json_ref_doc:
                plan_uri_str = json_ref_doc['plan_uri']

                # figure out if the plan uri is relative or absolute
                plan_uri = urllib.parse.urlparse(plan_uri_str)
                uri_path = plan_uri.path
                if not plan_uri.netloc:
                    # should be something like "../plans/<uuid>" or
                    # "/camp/v1_1/plans/<uuid> (include Solum plans)
                    if (not uri_path.startswith('../plans/')
                            and not uri_path.startswith('../../../v1/plans/')
                            and not uri_path.startswith('/camp/v1_1/plans/')
                            and not uri_path.startswith('/v1/plans/')):
                        msg = 'plan_uri does not reference a plan resource'
                        raise exception.BadRequest(reason=msg)

                    plan_uuid = plan_uri.path.split('/')[-1]

                else:
                    # We have an absolute URI. Try to figure out if it refers
                    # to a plan on this Solum instance. Note the following code
                    # does not support URI aliases. A request that contains
                    # a 'plan_uri' with a network location that is different
                    # than network location used to make this request but
                    # which, nevertheless, still refers to this Solum instance
                    # will experience a false negative. This code will treat
                    # that plan as if it existed on another CAMP-compliant
                    # server.
                    if plan_uri_str.startswith(pecan.request.host_url):
                        if (not uri_path.startswith('/camp/v1_1/plans/')
                                and not uri_path.startswith('/v1/plans/')):
                            msg = 'plan_uri does not reference a plan resource'
                            raise exception.BadRequest(reason=msg)

                        plan_uuid = plan_uri.path.split('/')[-1]

                    else:
                        # The plan exists on another server.
                        # TODO(gpilz): support references to plans on other
                        # servers
                        raise exception.NotImplemented()

                # resolve the local plan by its uuid. this will raise a
                # ResourceNotFound exception if there is no plan with
                # this uuid
                phandler = plan_handler.PlanHandler(
                    pecan.request.security_context)
                plan_obj = phandler.get(plan_uuid)

            elif 'pdp_uri' in json_ref_doc:
                # TODO(gpilz): support references to PDPs
                raise exception.NotImplemented()
            else:
                # must have either 'plan_uri' or 'pdp_uri'
                msg = 'JSON object must contain either plan_uri or pdp_uri'
                raise exception.BadRequest(reason=msg)
        else:
            # TODO(gpilz): support deploying an application by value
            raise exception.NotImplemented()

        # at this point we expect to have a reference to a plan database object
        # for the plan that will be used to create the application
        ahandler = assembly_handler.AssemblyHandler(
            pecan.request.security_context)
        assem_db_obj = ahandler.create_from_plan(plan_obj)
        assem_model = model.Assembly.from_db_model(assem_db_obj,
                                                   pecan.request.host_url)

        pecan.response.status = 201
        pecan.response.location = assem_model.uri
        return wsme_json.tojson(model.Assembly, assem_model)
예제 #25
0
    def post(self, trigger_id):
        """Trigger a new event on Solum."""
        commit_sha = ''
        status_url = None
        collab_url = None
        workflow = None

        try:
            query = query_dict(pecan.request.query_string)
            if 'workflow' in query:
                valid_stages = ['unittest', 'build', 'deploy']
                workflow = query['workflow'].replace('+', ' ').split(' ')
                workflow = filter(lambda x: x in valid_stages, workflow)
                if not workflow:
                    workflow = None
            body = json.loads(pecan.request.body)
            if ('sender' in body and 'url' in body['sender']
                    and 'api.github.com' in body['sender']['url']):
                if 'comment' in body:
                    # Process a request for rebuilding
                    phrase = body['comment']['body']
                    commenter = body['comment']['user']['login']
                    private_repo = body['repository']['private']
                    # An example of collab_url
                    # https://api.github.com/repos/:user/:repo/collaborators{/collaborator}
                    if not private_repo:
                        # Only verify collaborator for public repos
                        collab_url = (
                            body['repository']['collaborators_url'].format(
                                **{'/collaborator': '/' + commenter}))
                    if (phrase.strip('. ').lower() !=
                            CONF.api.rebuild_phrase.lower()):
                        err_msg = 'Rebuild phrase does not match'
                        raise exception.RequestForbidden(reason=err_msg)
                    else:
                        commit_sha = body['comment']['commit_id']
                elif 'pull_request' in body:
                    # Process a GitHub pull request
                    commit_sha = body['pull_request']['head']['sha']
                else:
                    raise exception.NotImplemented()

                # An example of Github statuses_url
                # https://api.github.com/repos/:user/:repo/statuses/{sha}
                if commit_sha:
                    status_url = body['repository']['statuses_url'].format(
                        sha=commit_sha)
            else:
                # Request NOT from a Github repo
                raise exception.NotImplemented()
        except Exception as exc:
            if isinstance(exc, exception.SolumException):
                raise
            info_msg = "Expected fields not found in request body."
            LOG.info(info_msg)
            raise exception.BadRequest(reason=info_msg)

        try:
            handler = app_handler.AppHandler(None)
            handler.trigger_workflow(trigger_id,
                                     commit_sha,
                                     status_url,
                                     collab_url,
                                     workflow=workflow)
        except exception.ResourceNotFound as e:
            LOG.error("Incorrect trigger url.")
            raise e

        pecan.response.status = 202
예제 #26
0
    def post(self):
        """Create a new CAMP-style plan."""
        if not pecan.request.body or len(pecan.request.body) < 1:
            raise exception.BadRequest

        # check to make sure the request has the right Content-Type
        if (pecan.request.content_type is None or
                pecan.request.content_type != 'application/x-yaml'):
            raise exception.UnsupportedMediaType(
                name=pecan.request.content_type,
                method='POST')

        try:
            yaml_input_plan = yamlutils.load(pecan.request.body)
        except ValueError as excp:
            raise exception.BadRequest(reason='Plan is invalid. '
                                       + six.text_type(excp))

        camp_version = yaml_input_plan.get('camp_version')
        if camp_version is None:
            raise exception.BadRequest(
                reason='camp_version attribute is missing from submitted Plan')
        elif camp_version != 'CAMP 1.1':
            raise exception.BadRequest(reason=UNSUP_VER_ERR % camp_version)

        # Use Solum's handler as the point of commonality. We can do this
        # because Solum stores plans in the DB in their JSON form.
        handler = (plan_handler.
                   PlanHandler(pecan.request.security_context))
        model_plan = model.Plan(**yaml_input_plan)

        # Move any inline Service Specifications to the "services" section.
        # This avoids an issue where WSME can't properly handle multi-typed
        # attributes (e.g. 'fulfillment'). It also smoothes out the primary
        # difference between CAMP plans and Solum plans, namely that Solum
        # plans don't have inline Service Specifications.
        for art in model_plan.artifacts:
            if art.requirements != wsme.Unset:
                for req in art.requirements:
                    if (req.fulfillment != wsme.Unset and
                        isinstance(req.fulfillment,
                                   model.ServiceSpecification)):
                        s_spec = req.fulfillment

                        # if the inline service spec doesn't have an id
                        # generate one
                        if s_spec.id == wsme.Unset:
                            s_spec.id = uuidutils.generate_uuid()

                        # move the inline service spec to the 'services'
                        # section
                        if model_plan.services == wsme.Unset:
                            model_plan.services = [s_spec]
                        else:
                            model_plan.services.append(s_spec)

                        # set the fulfillment to the service spec id
                        req.fulfillment = "id:%s" % s_spec.id

        db_obj = handler.create(clean_plan(wjson.tojson(model.Plan,
                                                        model_plan)))
        plan_dict = fluff_plan(db_obj.refined_content(), db_obj.uuid)

        pecan.response.status = 201
        pecan.response.location = plan_dict['uri']
        return plan_dict
예제 #27
0
 def error_func():
     raise exception.BadRequest(**error_args)
예제 #28
0
 def _validate(self, app_data):
     if not app_data.languagepack:
         raise exception.BadRequest(reason="Languagepack not specified.")