@exception.wrap_pecan_controller_exception
    @pecan.expose('json', content_type='application/x-yaml')
    def post(self):
        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 = str(uuid.uuid4())

                        # 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
Format multiple error messages.
dataset/ETHPy150Open openstack/solum/solum/api/controllers/camp/v1_1/plans.py/PlansController.post--crossover with--dataset/ETHPy150Open ganeti/ganeti/lib/cmdlib/cluster/verify.py/_VerifyErrors._ErrorMsgList