Esempio n. 1
0
class Controller(rest.RestController):
    """Version 1 API controller root."""

    nodes = node.NodesController()
    ports = port.PortsController()
    chassis = chassis.ChassisController()
    drivers = driver.DriversController()
    lookup = ramdisk.LookupController()
    heartbeat = ramdisk.HeartbeatController()

    @expose.expose(V1)
    def get(self):
        # NOTE: The reason why convert() it's being called for every
        #       request is because we need to get the host url from
        #       the request object to make the links.
        return V1.convert()

    def _check_version(self, version, headers=None):
        if headers is None:
            headers = {}
        # ensure that major version in the URL matches the header
        if version.major != BASE_VERSION:
            raise exc.HTTPNotAcceptable(
                _("Mutually exclusive versions requested. Version %(ver)s "
                  "requested but not supported by this service. The supported "
                  "version range is: [%(min)s, %(max)s].") % {
                      'ver': version,
                      'min': versions.MIN_VERSION_STRING,
                      'max': versions.MAX_VERSION_STRING
                  },
                headers=headers)
        # ensure the minor version is within the supported range
        if version < MIN_VER or version > MAX_VER:
            raise exc.HTTPNotAcceptable(
                _("Version %(ver)s was requested but the minor version is not "
                  "supported by this service. The supported version range is: "
                  "[%(min)s, %(max)s].") % {
                      'ver': version,
                      'min': versions.MIN_VERSION_STRING,
                      'max': versions.MAX_VERSION_STRING
                  },
                headers=headers)

    @pecan.expose()
    def _route(self, args):
        v = base.Version(pecan.request.headers, versions.MIN_VERSION_STRING,
                         versions.MAX_VERSION_STRING)

        # Always set the min and max headers
        pecan.response.headers[base.Version.min_string] = (
            versions.MIN_VERSION_STRING)
        pecan.response.headers[base.Version.max_string] = (
            versions.MAX_VERSION_STRING)

        # assert that requested version is supported
        self._check_version(v, pecan.response.headers)
        pecan.response.headers[base.Version.string] = str(v)
        pecan.request.version = v

        return super(Controller, self)._route(args)
Esempio n. 2
0
def _assess_db_object_and_api_performance(mock_log, mock_request):
    print('Phase - Assess DB & Object conversion Performance')
    _add_a_line()
    # Just mock it to silence it since getting the logger to update
    # config seems like not a thing once started. :\
    mock_log.debug = mock.Mock()
    # Internal logic requires major/minor versions and a context to
    # proceed. This is just to make the NodesController respond properly.
    mock_request.context = context.get_admin_context()
    mock_request.version.major = 1
    mock_request.version.minor = 71

    start = time.time()
    node_api_controller = node_api.NodesController()
    node_api_controller.context = context.get_admin_context()
    fields = ("uuid,power_state,target_power_state,provision_state,"
              "target_provision_state,last_error,maintenance,properties,"
              "instance_uuid,traits,resource_class")

    total_nodes = 0

    res = node_api_controller._get_nodes_collection(
        chassis_uuid=None,
        instance_uuid=None,
        associated=None,
        maintenance=None,
        retired=None,
        provision_state=None,
        marker=None,
        limit=None,
        sort_key="id",
        sort_dir="asc",
        fields=fields.split(','))
    total_nodes = len(res['nodes'])
    while len(res['nodes']) != 1:
        print(" ** Getting nodes ** %s Elapsed: %s seconds." %
              (total_nodes, _calculate_delta(start, time.time())))
        res = node_api_controller._get_nodes_collection(
            chassis_uuid=None,
            instance_uuid=None,
            associated=None,
            maintenance=None,
            retired=None,
            provision_state=None,
            marker=res['nodes'][-1]['uuid'],
            limit=None,
            sort_key="id",
            sort_dir="asc",
            fields=fields.split(','))
        new_nodes = len(res['nodes'])
        if new_nodes == 0:
            break
        total_nodes = total_nodes + new_nodes

    delta = _calculate_delta(start, time.time())
    print('Took %s seconds to return all %s nodes via '
          'nodes API call pattern.\n' % (delta, total_nodes))
Esempio n. 3
0
class Controller(rest.RestController):
    """Version 1 API controller root."""

    nodes = node.NodesController()
    ports = port.PortsController()
    chassis = chassis.ChassisController()

    @wsme_pecan.wsexpose(V1)
    def get(self):
        # NOTE: The reason why convert() it's being called for every
        #       request is because we need to get the host url from
        #       the request object to make the links.
        return V1.convert()
Esempio n. 4
0
class Controller(rest.RestController):
    """Version 1 API controller root."""

    nodes = node.NodesController()
    ports = port.PortsController()
    chassis = chassis.ChassisController()
    drivers = driver.DriversController()

    @wsme_pecan.wsexpose(V1)
    def get(self):
        # NOTE: The reason why convert() it's being called for every
        #       request is because we need to get the host url from
        #       the request object to make the links.
        return V1.convert()

    def _check_version(self, version):
        # ensure that major version in the URL matches the header
        if version.major != 1:
            raise exc.HTTPNotAcceptable(
                _("Mutually exclusive versions requested. Version %(ver)s "
                  "requested but not supported by this service.") %
                {'ver': version})
        # ensure the minor version is within the supported range
        if version.minor < MIN_VER or version.minor > MAX_VER:
            raise exc.HTTPNotAcceptable(
                _("Unsupported minor version requested. This API service "
                  "supports the following version range: "
                  "[%(min)s, %(max)s].") % {
                      'min': MIN_VER,
                      'max': MAX_VER
                  })

        version.set_min_max(MIN_VER, MAX_VER)

    @pecan.expose()
    def _route(self, args):
        v = base.Version(pecan.request.headers)
        # Always set the min and max headers
        # FIXME: these are not being sent if _check_version raises an exception
        pecan.response.headers[base.Version.min_string] = str(MIN_VER)
        pecan.response.headers[base.Version.max_string] = str(MAX_VER)

        # assert that requested version is supported
        self._check_version(v)
        pecan.response.headers[base.Version.string] = str(v)
        pecan.request.version = v

        return super(Controller, self)._route(args)
Esempio n. 5
0
class ChassisController(rest.RestController):
    """REST controller for Chassis."""

    nodes = node.NodesController()
    """Expose nodes as a sub-element of chassis"""

    # Set the flag to indicate that the requests to this resource are
    # coming from a top-level resource
    nodes.from_chassis = True

    _custom_actions = {
        'detail': ['GET'],
    }

    invalid_sort_key_list = ['extra']

    def _get_chassis_collection(self,
                                marker,
                                limit,
                                sort_key,
                                sort_dir,
                                resource_url=None,
                                fields=None,
                                detail=None):
        limit = api_utils.validate_limit(limit)
        sort_dir = api_utils.validate_sort_dir(sort_dir)
        marker_obj = None
        if marker:
            marker_obj = objects.Chassis.get_by_uuid(api.request.context,
                                                     marker)

        if sort_key in self.invalid_sort_key_list:
            raise exception.InvalidParameterValue(
                _("The sort_key value %(key)s is an invalid field for sorting")
                % {'key': sort_key})

        chassis = objects.Chassis.list(api.request.context,
                                       limit,
                                       marker_obj,
                                       sort_key=sort_key,
                                       sort_dir=sort_dir)
        parameters = {}
        if detail is not None:
            parameters['detail'] = detail

        return ChassisCollection.convert_with_links(chassis,
                                                    limit,
                                                    url=resource_url,
                                                    fields=fields,
                                                    sort_key=sort_key,
                                                    sort_dir=sort_dir,
                                                    **parameters)

    @METRICS.timer('ChassisController.get_all')
    @expose.expose(ChassisCollection, types.uuid, int, str, str,
                   types.listtype, types.boolean)
    def get_all(self,
                marker=None,
                limit=None,
                sort_key='id',
                sort_dir='asc',
                fields=None,
                detail=None):
        """Retrieve a list of chassis.

        :param marker: pagination marker for large data sets.
        :param limit: maximum number of resources to return in a single result.
                      This value cannot be larger than the value of max_limit
                      in the [api] section of the ironic configuration, or only
                      max_limit resources will be returned.
        :param sort_key: column to sort results by. Default: id.
        :param sort_dir: direction to sort. "asc" or "desc". Default: asc.
        :param fields: Optional, a list with a specified set of fields
            of the resource to be returned.
        """
        cdict = api.request.context.to_policy_values()
        policy.authorize('baremetal:chassis:get', cdict, cdict)

        api_utils.check_allow_specify_fields(fields)

        fields = api_utils.get_request_return_fields(fields, detail,
                                                     _DEFAULT_RETURN_FIELDS)

        return self._get_chassis_collection(marker,
                                            limit,
                                            sort_key,
                                            sort_dir,
                                            fields=fields,
                                            detail=detail)

    @METRICS.timer('ChassisController.detail')
    @expose.expose(ChassisCollection, types.uuid, int, str, str)
    def detail(self, marker=None, limit=None, sort_key='id', sort_dir='asc'):
        """Retrieve a list of chassis with detail.

        :param marker: pagination marker for large data sets.
        :param limit: maximum number of resources to return in a single result.
                      This value cannot be larger than the value of max_limit
                      in the [api] section of the ironic configuration, or only
                      max_limit resources will be returned.
        :param sort_key: column to sort results by. Default: id.
        :param sort_dir: direction to sort. "asc" or "desc". Default: asc.
        """
        cdict = api.request.context.to_policy_values()
        policy.authorize('baremetal:chassis:get', cdict, cdict)

        # /detail should only work against collections
        parent = api.request.path.split('/')[:-1][-1]
        if parent != "chassis":
            raise exception.HTTPNotFound()

        resource_url = '/'.join(['chassis', 'detail'])
        return self._get_chassis_collection(marker, limit, sort_key, sort_dir,
                                            resource_url)

    @METRICS.timer('ChassisController.get_one')
    @expose.expose(Chassis, types.uuid, types.listtype)
    def get_one(self, chassis_uuid, fields=None):
        """Retrieve information about the given chassis.

        :param chassis_uuid: UUID of a chassis.
        :param fields: Optional, a list with a specified set of fields
            of the resource to be returned.
        """
        cdict = api.request.context.to_policy_values()
        policy.authorize('baremetal:chassis:get', cdict, cdict)

        api_utils.check_allow_specify_fields(fields)
        rpc_chassis = objects.Chassis.get_by_uuid(api.request.context,
                                                  chassis_uuid)
        return Chassis.convert_with_links(rpc_chassis, fields=fields)

    @METRICS.timer('ChassisController.post')
    @expose.expose(Chassis, body=Chassis, status_code=http_client.CREATED)
    def post(self, chassis):
        """Create a new chassis.

        :param chassis: a chassis within the request body.
        """
        context = api.request.context
        cdict = context.to_policy_values()
        policy.authorize('baremetal:chassis:create', cdict, cdict)

        # NOTE(yuriyz): UUID is mandatory for notifications payload
        if not chassis.uuid:
            chassis.uuid = uuidutils.generate_uuid()

        new_chassis = objects.Chassis(context, **chassis.as_dict())
        notify.emit_start_notification(context, new_chassis, 'create')
        with notify.handle_error_notification(context, new_chassis, 'create'):
            new_chassis.create()
        notify.emit_end_notification(context, new_chassis, 'create')
        # Set the HTTP Location Header
        api.response.location = link.build_url('chassis', new_chassis.uuid)
        return Chassis.convert_with_links(new_chassis)

    @METRICS.timer('ChassisController.patch')
    @expose.validate(types.uuid, [ChassisPatchType])
    @expose.expose(Chassis, types.uuid, body=[ChassisPatchType])
    def patch(self, chassis_uuid, patch):
        """Update an existing chassis.

        :param chassis_uuid: UUID of a chassis.
        :param patch: a json PATCH document to apply to this chassis.
        """
        context = api.request.context
        cdict = context.to_policy_values()
        policy.authorize('baremetal:chassis:update', cdict, cdict)

        rpc_chassis = objects.Chassis.get_by_uuid(context, chassis_uuid)
        chassis = Chassis(
            **api_utils.apply_jsonpatch(rpc_chassis.as_dict(), patch))

        # Update only the fields that have changed
        for field in objects.Chassis.fields:
            try:
                patch_val = getattr(chassis, field)
            except AttributeError:
                # Ignore fields that aren't exposed in the API
                continue
            if patch_val == atypes.Unset:
                patch_val = None
            if rpc_chassis[field] != patch_val:
                rpc_chassis[field] = patch_val

        notify.emit_start_notification(context, rpc_chassis, 'update')
        with notify.handle_error_notification(context, rpc_chassis, 'update'):
            rpc_chassis.save()
        notify.emit_end_notification(context, rpc_chassis, 'update')
        return Chassis.convert_with_links(rpc_chassis)

    @METRICS.timer('ChassisController.delete')
    @expose.expose(None, types.uuid, status_code=http_client.NO_CONTENT)
    def delete(self, chassis_uuid):
        """Delete a chassis.

        :param chassis_uuid: UUID of a chassis.
        """
        context = api.request.context
        cdict = context.to_policy_values()
        policy.authorize('baremetal:chassis:delete', cdict, cdict)

        rpc_chassis = objects.Chassis.get_by_uuid(context, chassis_uuid)
        notify.emit_start_notification(context, rpc_chassis, 'delete')
        with notify.handle_error_notification(context, rpc_chassis, 'delete'):
            rpc_chassis.destroy()
        notify.emit_end_notification(context, rpc_chassis, 'delete')
Esempio n. 6
0
class ChassisController(rest.RestController):
    """REST controller for Chassis."""

    nodes = node.NodesController()
    "Expose nodes as a sub-element of chassis"

    # Set the flag to indicate that the requests to this resource are
    # coming from a top-level resource
    nodes.from_chassis = True

    _custom_actions = {
        'detail': ['GET'],
    }

    def _get_chassis_collection(self,
                                marker,
                                limit,
                                sort_key,
                                sort_dir,
                                expand=False,
                                resource_url=None):
        limit = api_utils.validate_limit(limit)
        sort_dir = api_utils.validate_sort_dir(sort_dir)
        marker_obj = None
        if marker:
            marker_obj = objects.Chassis.get_by_uuid(pecan.request.context,
                                                     marker)
        chassis = objects.Chassis.list(pecan.request.context,
                                       limit,
                                       marker_obj,
                                       sort_key=sort_key,
                                       sort_dir=sort_dir)
        return ChassisCollection.convert_with_links(chassis,
                                                    limit,
                                                    url=resource_url,
                                                    expand=expand,
                                                    sort_key=sort_key,
                                                    sort_dir=sort_dir)

    @wsme_pecan.wsexpose(ChassisCollection, types.uuid, int, wtypes.text,
                         wtypes.text)
    def get_all(self, marker=None, limit=None, sort_key='id', sort_dir='asc'):
        """Retrieve a list of chassis.

        :param marker: pagination marker for large data sets.
        :param limit: maximum number of resources to return in a single result.
        :param sort_key: column to sort results by. Default: id.
        :param sort_dir: direction to sort. "asc" or "desc". Default: asc.
        """
        return self._get_chassis_collection(marker, limit, sort_key, sort_dir)

    @wsme_pecan.wsexpose(ChassisCollection, types.uuid, int, wtypes.text,
                         wtypes.text)
    def detail(self, marker=None, limit=None, sort_key='id', sort_dir='asc'):
        """Retrieve a list of chassis with detail.

        :param marker: pagination marker for large data sets.
        :param limit: maximum number of resources to return in a single result.
        :param sort_key: column to sort results by. Default: id.
        :param sort_dir: direction to sort. "asc" or "desc". Default: asc.
        """
        # /detail should only work agaist collections
        parent = pecan.request.path.split('/')[:-1][-1]
        if parent != "chassis":
            raise exception.HTTPNotFound

        expand = True
        resource_url = '/'.join(['chassis', 'detail'])
        return self._get_chassis_collection(marker, limit, sort_key, sort_dir,
                                            expand, resource_url)

    @wsme_pecan.wsexpose(Chassis, types.uuid)
    def get_one(self, chassis_uuid):
        """Retrieve information about the given chassis.

        :param chassis_uuid: UUID of a chassis.
        """
        rpc_chassis = objects.Chassis.get_by_uuid(pecan.request.context,
                                                  chassis_uuid)
        return Chassis.convert_with_links(rpc_chassis)

    @wsme_pecan.wsexpose(Chassis, body=Chassis, status_code=201)
    def post(self, chassis):
        """Create a new chassis.

        :param chassis: a chassis within the request body.
        """
        new_chassis = objects.Chassis(pecan.request.context,
                                      **chassis.as_dict())
        new_chassis.create()
        # Set the HTTP Location Header
        pecan.response.location = link.build_url('chassis', new_chassis.uuid)
        return Chassis.convert_with_links(new_chassis)

    @wsme.validate(types.uuid, [ChassisPatchType])
    @wsme_pecan.wsexpose(Chassis, types.uuid, body=[ChassisPatchType])
    def patch(self, chassis_uuid, patch):
        """Update an existing chassis.

        :param chassis_uuid: UUID of a chassis.
        :param patch: a json PATCH document to apply to this chassis.
        """
        rpc_chassis = objects.Chassis.get_by_uuid(pecan.request.context,
                                                  chassis_uuid)
        try:
            chassis = Chassis(
                **api_utils.apply_jsonpatch(rpc_chassis.as_dict(), patch))
        except api_utils.JSONPATCH_EXCEPTIONS as e:
            raise exception.PatchError(patch=patch, reason=e)

        # Update only the fields that have changed
        for field in objects.Chassis.fields:
            try:
                patch_val = getattr(chassis, field)
            except AttributeError:
                # Ignore fields that aren't exposed in the API
                continue
            if rpc_chassis[field] != patch_val:
                rpc_chassis[field] = patch_val

        rpc_chassis.save()
        return Chassis.convert_with_links(rpc_chassis)

    @wsme_pecan.wsexpose(None, types.uuid, status_code=204)
    def delete(self, chassis_uuid):
        """Delete a chassis.

        :param chassis_uuid: UUID of a chassis.
        """
        rpc_chassis = objects.Chassis.get_by_uuid(pecan.request.context,
                                                  chassis_uuid)
        rpc_chassis.destroy()
Esempio n. 7
0
class ChassisController(rest.RestController):
    """REST controller for Chassis."""

    nodes = node.NodesController()
    """Expose nodes as a sub-element of chassis"""

    # Set the flag to indicate that the requests to this resource are
    # coming from a top-level resource
    nodes.from_chassis = True

    _custom_actions = {
        'detail': ['GET'],
    }

    invalid_sort_key_list = ['extra']

    def _get_chassis_collection(self, marker, limit, sort_key, sort_dir,
                                resource_url=None, fields=None):
        limit = api_utils.validate_limit(limit)
        sort_dir = api_utils.validate_sort_dir(sort_dir)
        marker_obj = None
        if marker:
            marker_obj = objects.Chassis.get_by_uuid(pecan.request.context,
                                                     marker)

        if sort_key in self.invalid_sort_key_list:
            raise exception.InvalidParameterValue(
                _("The sort_key value %(key)s is an invalid field for sorting")
                % {'key': sort_key})

        chassis = objects.Chassis.list(pecan.request.context, limit,
                                       marker_obj, sort_key=sort_key,
                                       sort_dir=sort_dir)
        return ChassisCollection.convert_with_links(chassis, limit,
                                                    url=resource_url,
                                                    fields=fields,
                                                    sort_key=sort_key,
                                                    sort_dir=sort_dir)

    @expose.expose(ChassisCollection, types.uuid, int,
                   wtypes.text, wtypes.text, types.listtype)
    def get_all(self, marker=None, limit=None, sort_key='id', sort_dir='asc',
                fields=None):
        """Retrieve a list of chassis.

        :param marker: pagination marker for large data sets.
        :param limit: maximum number of resources to return in a single result.
        :param sort_key: column to sort results by. Default: id.
        :param sort_dir: direction to sort. "asc" or "desc". Default: asc.
        :param fields: Optional, a list with a specified set of fields
            of the resource to be returned.
        """
        api_utils.check_allow_specify_fields(fields)
        if fields is None:
            fields = _DEFAULT_RETURN_FIELDS
        return self._get_chassis_collection(marker, limit, sort_key, sort_dir,
                                            fields=fields)

    @expose.expose(ChassisCollection, types.uuid, int,
                   wtypes.text, wtypes.text)
    def detail(self, marker=None, limit=None, sort_key='id', sort_dir='asc'):
        """Retrieve a list of chassis with detail.

        :param marker: pagination marker for large data sets.
        :param limit: maximum number of resources to return in a single result.
        :param sort_key: column to sort results by. Default: id.
        :param sort_dir: direction to sort. "asc" or "desc". Default: asc.
        """
        # /detail should only work against collections
        parent = pecan.request.path.split('/')[:-1][-1]
        if parent != "chassis":
            raise exception.HTTPNotFound()

        resource_url = '/'.join(['chassis', 'detail'])
        return self._get_chassis_collection(marker, limit, sort_key, sort_dir,
                                            resource_url)

    @expose.expose(Chassis, types.uuid, types.listtype)
    def get_one(self, chassis_uuid, fields=None):
        """Retrieve information about the given chassis.

        :param chassis_uuid: UUID of a chassis.
        :param fields: Optional, a list with a specified set of fields
            of the resource to be returned.
        """
        api_utils.check_allow_specify_fields(fields)
        rpc_chassis = objects.Chassis.get_by_uuid(pecan.request.context,
                                                  chassis_uuid)
        return Chassis.convert_with_links(rpc_chassis, fields=fields)

    @expose.expose(Chassis, body=Chassis, status_code=http_client.CREATED)
    def post(self, chassis):
        """Create a new chassis.

        :param chassis: a chassis within the request body.
        """
        new_chassis = objects.Chassis(pecan.request.context,
                                      **chassis.as_dict())
        new_chassis.create()
        # Set the HTTP Location Header
        pecan.response.location = link.build_url('chassis', new_chassis.uuid)
        return Chassis.convert_with_links(new_chassis)

    @wsme.validate(types.uuid, [ChassisPatchType])
    @expose.expose(Chassis, types.uuid, body=[ChassisPatchType])
    def patch(self, chassis_uuid, patch):
        """Update an existing chassis.

        :param chassis_uuid: UUID of a chassis.
        :param patch: a json PATCH document to apply to this chassis.
        """
        rpc_chassis = objects.Chassis.get_by_uuid(pecan.request.context,
                                                  chassis_uuid)
        try:
            chassis = Chassis(
                **api_utils.apply_jsonpatch(rpc_chassis.as_dict(), patch))

        except api_utils.JSONPATCH_EXCEPTIONS as e:
            raise exception.PatchError(patch=patch, reason=e)

        # Update only the fields that have changed
        for field in objects.Chassis.fields:
            try:
                patch_val = getattr(chassis, field)
            except AttributeError:
                # Ignore fields that aren't exposed in the API
                continue
            if patch_val == wtypes.Unset:
                patch_val = None
            if rpc_chassis[field] != patch_val:
                rpc_chassis[field] = patch_val

        rpc_chassis.save()
        return Chassis.convert_with_links(rpc_chassis)

    @expose.expose(None, types.uuid, status_code=http_client.NO_CONTENT)
    def delete(self, chassis_uuid):
        """Delete a chassis.

        :param chassis_uuid: UUID of a chassis.
        """
        rpc_chassis = objects.Chassis.get_by_uuid(pecan.request.context,
                                                  chassis_uuid)
        rpc_chassis.destroy()
Esempio n. 8
0
class Controller(rest.RestController):
    """Version 1 API controller root."""

    nodes = node.NodesController()
    ports = port.PortsController()
    portgroups = portgroup.PortgroupsController()
    chassis = chassis.ChassisController()
    drivers = driver.DriversController()
    volume = volume.VolumeController()
    lookup = ramdisk.LookupController()
    heartbeat = ramdisk.HeartbeatController()
    conductors = conductor.ConductorsController()
    allocations = allocation.AllocationsController()
    events = event.EventsController()
    deploy_templates = deploy_template.DeployTemplatesController()

    @expose.expose(V1)
    def get(self):
        # NOTE: The reason why convert() it's being called for every
        #       request is because we need to get the host url from
        #       the request object to make the links.
        return V1.convert()

    def _check_version(self, version, headers=None):
        if headers is None:
            headers = {}
        # ensure that major version in the URL matches the header
        if version.major != BASE_VERSION:
            raise exc.HTTPNotAcceptable(
                _("Mutually exclusive versions requested. Version %(ver)s "
                  "requested but not supported by this service. The supported "
                  "version range is: [%(min)s, %(max)s].") % {
                      'ver': version,
                      'min': versions.min_version_string(),
                      'max': versions.max_version_string()
                  },
                headers=headers)
        # ensure the minor version is within the supported range
        if version < min_version() or version > max_version():
            raise exc.HTTPNotAcceptable(
                _("Version %(ver)s was requested but the minor version is not "
                  "supported by this service. The supported version range is: "
                  "[%(min)s, %(max)s].") % {
                      'ver': version,
                      'min': versions.min_version_string(),
                      'max': versions.max_version_string()
                  },
                headers=headers)

    @pecan.expose()
    def _route(self, args, request=None):
        v = base.Version(api.request.headers, versions.min_version_string(),
                         versions.max_version_string())

        # Always set the min and max headers
        api.response.headers[base.Version.min_string] = (
            versions.min_version_string())
        api.response.headers[base.Version.max_string] = (
            versions.max_version_string())

        # assert that requested version is supported
        self._check_version(v, api.response.headers)
        api.response.headers[base.Version.string] = str(v)
        api.request.version = v

        return super(Controller, self)._route(args, request)
Esempio n. 9
0
class Controller(object):
    """Version 1 API controller root."""

    _subcontroller_map = {
        'nodes': node.NodesController(),
        'ports': port.PortsController(),
        'portgroups': portgroup.PortgroupsController(),
        'chassis': chassis.ChassisController(),
        'drivers': driver.DriversController(),
        'volume': volume.VolumeController(),
        'lookup': ramdisk.LookupController(),
        'heartbeat': ramdisk.HeartbeatController(),
        'conductors': conductor.ConductorsController(),
        'allocations': allocation.AllocationsController(),
        'events': event.EventsController(),
        'deploy_templates': deploy_template.DeployTemplatesController()
    }

    @method.expose()
    def index(self):
        # NOTE: The reason why v1() it's being called for every
        #       request is because we need to get the host url from
        #       the request object to make the links.
        self._add_version_attributes()
        if api.request.method != "GET":
            pecan.abort(http_client.METHOD_NOT_ALLOWED)

        return v1()

    def _check_version(self, version, headers=None):
        if headers is None:
            headers = {}
        # ensure that major version in the URL matches the header
        if version.major != BASE_VERSION:
            raise exc.HTTPNotAcceptable(
                _("Mutually exclusive versions requested. Version %(ver)s "
                  "requested but not supported by this service. The supported "
                  "version range is: [%(min)s, %(max)s].") % {
                      'ver': version,
                      'min': versions.min_version_string(),
                      'max': versions.max_version_string()
                  },
                headers=headers)
        # ensure the minor version is within the supported range
        if version < min_version() or version > max_version():
            raise exc.HTTPNotAcceptable(
                _("Version %(ver)s was requested but the minor version is not "
                  "supported by this service. The supported version range is: "
                  "[%(min)s, %(max)s].") % {
                      'ver': version,
                      'min': versions.min_version_string(),
                      'max': versions.max_version_string()
                  },
                headers=headers)

    def _add_version_attributes(self):
        v = base.Version(api.request.headers, versions.min_version_string(),
                         versions.max_version_string())

        # Always set the min and max headers
        api.response.headers[base.Version.min_string] = (
            versions.min_version_string())
        api.response.headers[base.Version.max_string] = (
            versions.max_version_string())

        # assert that requested version is supported
        self._check_version(v, api.response.headers)
        api.response.headers[base.Version.string] = str(v)
        api.request.version = v

    @pecan.expose()
    def _lookup(self, primary_key, *remainder):
        self._add_version_attributes()

        controller = self._subcontroller_map.get(primary_key)
        if not controller:
            pecan.abort(http_client.NOT_FOUND)

        return controller, remainder