Esempio n. 1
0
class AddressPoolPatchType(types.JsonPatchType):
    """A complex type that represents a single json-patch operation."""

    value = types.MultiType([wtypes.text, [list]])

    @staticmethod
    def mandatory_attrs():
        """These attributes cannot be removed."""
        result = (super(AddressPoolPatchType,
                        AddressPoolPatchType).mandatory_attrs())
        result.append(['/name', '/network', '/prefix', '/order', '/ranges'])
        return result

    @staticmethod
    def readonly_attrs():
        """These attributes cannot be updated."""
        # Once the initial configuration is complete, pool resizing is
        # disallowed
        if cutils.is_initial_config_complete():
            return ['/network', '/prefix']
        else:
            return ['/network']

    @staticmethod
    def validate(patch):
        result = (super(AddressPoolPatchType,
                        AddressPoolPatchType).validate(patch))
        if patch.op in ['add', 'remove']:
            msg = _("Attributes cannot be added or removed")
            raise wsme.exc.ClientSideError(msg % patch.path)
        if patch.path in patch.readonly_attrs():
            msg = _("'%s' is a read-only attribute and can not be updated")
            raise wsme.exc.ClientSideError(msg % patch.path)
        return result
Esempio n. 2
0
class ClusterPatchType(types.JsonPatchType):
    """A complex type that represents a single json-patch operation."""

    value = types.MultiType([wtypes.text, [list]])

    @staticmethod
    def mandatory_attrs():
        """These attributes cannot be removed."""
        result = (super(ClusterPatchType, ClusterPatchType).mandatory_attrs())
        result.append(['/name', '/peers'])
        return result

    @staticmethod
    def readonly_attrs():
        """These attributes cannot be updated."""
        return ['/name', '/type']

    @staticmethod
    def validate(patch):
        result = (super(ClusterPatchType, ClusterPatchType).validate(patch))
        if patch.op in ['add', 'remove']:
            msg = _("Attributes cannot be added or removed")
            raise wsme.exc.ClientSideError(msg % patch.path)
        if patch.path in patch.readonly_attrs():
            msg = _("'%s' is a read-only attribute and can not be updated")
            raise wsme.exc.ClientSideError(msg % patch.path)
        return result
Esempio n. 3
0
class Certificate(base.APIBase):
    """API representation of CERTIFICATE Configuration.

    This class enforces type checking and value constraints, and converts
    between the internal object model and the API representation of
    a certificate.
    """

    uuid = types.uuid
    "Unique UUID for this certificate"

    certtype = wtypes.text
    "Represents the type of certificate"

    issuer = wtypes.text
    "Represents the certificate issuer"

    signature = wtypes.text
    "Represents the certificate signature"

    start_date = wtypes.datetime.datetime
    "Represents the certificate start date"

    expiry_date = wtypes.datetime.datetime
    "Represents the certificate expiry"

    passphrase = wtypes.text
    "Represents the passphrase for pem"

    mode = wtypes.text
    "Represents the desired mode"

    details = types.MultiType({dict})
    "Represents additional details of the certificate"

    updated_at = wtypes.datetime.datetime

    def __init__(self, **kwargs):
        self.fields = list(objects.certificate.fields.keys())
        for k in self.fields:
            if not hasattr(self, k):
                continue
            setattr(self, k, kwargs.get(k, wtypes.Unset))

        # 'details' is not part of the object.certificate.fields
        # (it is an API-only attribute)
        self.fields.append('details')
        setattr(self, 'details', kwargs.get('details', None))

    @classmethod
    def convert_with_links(cls, rpc_certificate, expand=False):
        certificate = Certificate(**rpc_certificate.as_dict())
        if not expand:
            certificate.unset_fields_except([
                'uuid', 'certtype', 'issuer', 'signature', 'details',
                'start_date', 'expiry_date'
            ])

        # insert details for this certificate if they exist
        certificate = _insert_certificate_details(certificate)

        certificate.links = \
            [link.Link.make_link('self', pecan.request.host_url,
                                 'certificates', certificate.uuid),
             link.Link.make_link('bookmark', pecan.request.host_url,
                                 'certificates', certificate.uuid,
                                 bookmark=True)]

        return certificate
Esempio n. 4
0
class AddressPool(base.APIBase):
    """API representation of an IP address pool.

    This class enforces type checking and value constraints, and converts
    between the internal object model and the API representation of an IP
    address pool.
    """

    id = int
    "Unique ID for this address"

    uuid = types.uuid
    "Unique UUID for this address"

    name = wtypes.text
    "User defined name of the address pool"

    network = types.ipaddress
    "Network IP address"

    prefix = int
    "Network IP prefix length"

    order = wtypes.text
    "Address allocation scheme order"

    controller0_address = types.ipaddress
    "Controller-0 IP address"

    controller0_address_id = int
    "Represent the ID of the controller-0 IP address."

    controller1_address = types.ipaddress
    "Controller-1 IP address"

    controller1_address_id = int
    "Represent the ID of the controller-1 IP address."

    floating_address = types.ipaddress
    "Represent the floating IP address."

    floating_address_id = int
    "Represent the ID of the floating IP address."

    gateway_address = types.ipaddress
    "Represent the ID of the gateway IP address."

    gateway_address_id = int
    "Represent the ID of the gateway IP address."

    ranges = types.MultiType([[list]])
    "List of start-end pairs of IP address"

    def __init__(self, **kwargs):
        self.fields = objects.address_pool.fields.keys()
        for k in self.fields:
            if not hasattr(self, k):
                # Skip fields that we choose to hide
                continue
            setattr(self, k, kwargs.get(k, wtypes.Unset))

    def _get_family(self):
        value = netaddr.IPAddress(self.network)
        return value.version

    def as_dict(self):
        """
        Sets additional DB only attributes when converting from an API object
        type to a dictionary that will be used to populate the DB.
        """
        data = super(AddressPool, self).as_dict()
        data['family'] = self._get_family()
        return data

    @classmethod
    def convert_with_links(cls, rpc_addrpool, expand=True):
        pool = AddressPool(**rpc_addrpool.as_dict())
        if not expand:
            pool.unset_fields_except([
                'uuid', 'name', 'network', 'prefix', 'order', 'ranges',
                'controller0_address', 'controller0_address_id',
                'controller1_address', 'controller1_address_id',
                'floating_address', 'floating_address_id', 'gateway_address',
                'gateway_address_id'
            ])
        return pool

    @classmethod
    def _validate_name(cls, name):
        if len(name) < 1:
            raise ValueError(_("Name must not be an empty string"))

    @classmethod
    def _validate_prefix(cls, prefix):
        if prefix < 1:
            raise ValueError(_("Address prefix must be greater than 1"))

    @classmethod
    def _validate_zero_network(cls, network, prefix):
        data = netaddr.IPNetwork(network + "/" + str(prefix))
        network = data.network
        if network.value == 0:
            raise ValueError(_("Network must not be null"))

    @classmethod
    def _validate_network(cls, network, prefix):
        """
        Validates that the prefix is valid for the IP address family.
        """
        try:
            value = netaddr.IPNetwork(network + "/" + str(prefix))
        except netaddr.core.AddrFormatError:
            raise ValueError(_("Invalid IP address and prefix"))
        mask = value.hostmask
        host = value.ip & mask
        if host.value != 0:
            raise ValueError(_("Host bits must be zero"))

    @classmethod
    def _validate_network_type(cls, network):
        address = netaddr.IPAddress(network)
        if not address.is_unicast() and not address.is_multicast():
            raise ValueError(
                _("Network address must be a unicast address or"
                  "a multicast address"))

    @classmethod
    def _validate_allocation_order(cls, order):
        if order and order not in VALID_ALLOCATION_ORDER:
            raise ValueError(
                _("Network address allocation order must be one "
                  "of: %s") % ', '.join(VALID_ALLOCATION_ORDER))

    def validate_syntax(self):
        """
        Validates the syntax of each field.
        """
        self._validate_name(self.name)
        self._validate_prefix(self.prefix)
        self._validate_zero_network(self.network, self.prefix)
        self._validate_network(self.network, self.prefix)
        self._validate_network_type(self.network)
        self._validate_allocation_order(self.order)
Esempio n. 5
0
class Cluster(base.APIBase):
    """API representation of a Cluster.

    This class enforces type checking and value constraints, and converts
    between the internal object model and the API representation of a Cluster.
    """

    id = int
    "Unique ID for this cluster"

    uuid = types.uuid
    "Unique UUID for this cluster representation"

    cluster_uuid = types.uuid
    "The Unique UUID of the cluster"

    type = wtypes.text
    "Defined type of the cluster"

    name = wtypes.text
    "User defined name of the cluster"

    deployment_model = wtypes.text
    "Deployment model used by cluster"

    peers = types.MultiType([list])
    "List of peers info in the cluster"

    tiers = types.MultiType([list])
    "List of storage tier info in the cluster"

    links = [link.Link]
    "A list containing a self link and associated cluster links"

    storage_tiers = [link.Link]
    "Links to the collection of storage tiers on this cluster"

    def __init__(self, **kwargs):
        self.fields = objects.cluster.fields.keys()
        for k in self.fields:
            if not hasattr(self, k):
                # Skip fields that we choose to hide
                continue
            setattr(self, k, kwargs.get(k, wtypes.Unset))

    def as_dict(self):
        """
        Sets additional DB only attributes when converting from an API object
        type to a dictionary that will be used to populate the DB.
        """
        data = super(Cluster, self).as_dict()
        return data

    @classmethod
    def convert_with_links(cls, rpc_cluster, expand=True):
        cluster = Cluster(**rpc_cluster.as_dict())
        if not expand:
            cluster.unset_fields_except([
                'uuid', 'cluster_uuid', 'type', 'name', 'peers', 'tiers',
                'deployment_model'
            ])

        # All Ceph type clusters have the same storage model
        if cluster.type == constants.CLUSTER_TYPE_CEPH:
            try:
                # Storage model is defined dynamically, displayed by CLI
                # and used by Horizon.
                cluster.deployment_model = ceph.get_ceph_storage_model()
            except Exception:
                cluster.deployment_model = constants.CEPH_UNDEFINED_MODEL
        else:
            cluster.deployment_model = None

        cluster.links = [
            link.Link.make_link('self', pecan.request.host_url, 'clusters',
                                cluster.uuid),
            link.Link.make_link('bookmark',
                                pecan.request.host_url,
                                'clusters',
                                cluster.uuid,
                                bookmark=True)
        ]
        if expand:
            cluster.storage_tiers = [
                link.Link.make_link('self', pecan.request.host_url, 'clusters',
                                    cluster.uuid + "/storage_tiers"),
                link.Link.make_link('bookmark',
                                    pecan.request.host_url,
                                    'clusters',
                                    cluster.uuid + "/storage_tiers",
                                    bookmark=True)
            ]

        return cluster

    @classmethod
    def _validate_name(cls, name):
        if len(name) < 1:
            raise ValueError(_("Name must not be an empty string"))

    @classmethod
    def _validate_type(cls, type):
        if type and len(type) < 1:
            raise ValueError(_("Cluster type must not be an empty string"))

    def validate_syntax(self):
        """
        Validates the syntax of each field.
        """
        self._validate_name(self.name)
        self._validate_type(self.type)
Esempio n. 6
0
class DeviceImage(base.APIBase):
    """API representation of a device_image.

    This class enforces type checking and value constraints, and converts
    between the internal object model and the API representation of
    a device image.
    """

    id = int
    "Unique ID for this device_image"

    uuid = types.uuid
    "Unique UUID for this device_image"

    bitstream_type = wtypes.text
    "The bitstream type of the device image"

    pci_vendor = wtypes.text
    "The vendor ID of the pci device"

    pci_device = wtypes.text
    "The device ID of the pci device"

    bitstream_id = wtypes.text
    "The bitstream id of the functional device image"

    key_signature = wtypes.text
    "The key signature of the root-key device image"

    revoke_key_id = int
    "The key revocation id of the key revocation device image"

    name = wtypes.text
    "The name of the device image"

    description = wtypes.text
    "The description of the device image"

    image_version = wtypes.text
    "The version of the device image"

    applied = bool
    "Represent current status: created or applied"

    applied_labels = types.MultiType([list])
    "Represent a list of key-value pair of labels"

    def __init__(self, **kwargs):
        self.fields = list(objects.device_image.fields.keys())
        for k in self.fields:
            setattr(self, k, kwargs.get(k))

        # API-only attribute
        self.fields.append('action')
        setattr(self, 'action', kwargs.get('action', None))

        # 'applied_labels' is not part of the object.device_image.fields
        # (it is an API-only attribute)
        self.fields.append('applied_labels')
        setattr(self, 'applied_labels', kwargs.get('applied_labels', None))

    @classmethod
    def convert_with_links(cls, rpc_device_image, expand=True):
        device_image = DeviceImage(**rpc_device_image.as_dict())
        if not expand:
            device_image.unset_fields_except([
                'id', 'uuid', 'bitstream_type', 'pci_vendor', 'pci_device',
                'bitstream_id', 'key_signature', 'revoke_key_id', 'name',
                'description', 'image_version', 'applied', 'applied_labels'
            ])

        # insert applied labels for this device image if they exist
        device_image = _get_applied_labels(device_image)

        # do not expose the id attribute
        device_image.id = wtypes.Unset

        return device_image

    def _validate_bitstream_type(self):
        if self.bitstream_type not in ALLOWED_BITSTREAM_TYPES:
            raise ValueError(
                _("Bitstream type %s not supported") % self.bitstream_type)

    def validate_syntax(self):
        """
        Validates the syntax of each field.
        """
        self._validate_bitstream_type()
Esempio n. 7
0
class StorageTier(base.APIBase):
    """API representation of a Storage Tier.

    This class enforces type checking and value constraints, and converts
    between the internal object model and the API representation of
    a storage tier.
    """

    uuid = types.uuid
    "Unique UUID for this storage tier"

    name = wtypes.text
    "Storage tier name"

    type = wtypes.text
    "Storage tier type"

    status = wtypes.text
    "Storage tier status"

    capabilities = {
        wtypes.text: utils.ValidTypes(wtypes.text, six.integer_types)
    }
    "Storage tier meta data"

    forbackendid = int
    "The storage backend that is using this storage tier"

    backend_uuid = types.uuid
    "The UUID of the storage backend that is using this storage tier"

    forclusterid = int
    "The storage cluster that this storage tier belongs to"

    cluster_uuid = types.uuid
    "The UUID of the storage cluster this storage tier belongs to"

    stors = types.MultiType([list])
    "List of OSD ids associated with this tier"

    links = [link.Link]
    "A list containing a self link and associated storage tier links"

    istors = [link.Link]
    "Links to the collection of OSDs on this storage tier"

    def __init__(self, **kwargs):
        self.fields = objects.storage_tier.fields.keys()
        for k in self.fields:
            setattr(self, k, kwargs.get(k))

        if not self.uuid:
            self.uuid = uuidutils.generate_uuid()

    @classmethod
    def convert_with_links(cls, rpc_tier, expand=True):
        tier = StorageTier(**rpc_tier.as_dict())
        if not expand:
            tier.unset_fields_except([
                'uuid', 'name', 'type', 'status', 'capabilities',
                'backend_uuid', 'cluster_uuid', 'stors', 'created_at',
                'updated_at'
            ])

        # Don't expose ID attributes.
        tier.forbackendid = wtypes.Unset
        tier.forclusterid = wtypes.Unset

        tier.links = [
            link.Link.make_link('self', pecan.request.host_url,
                                'storage_tiers', tier.uuid),
            link.Link.make_link('bookmark',
                                pecan.request.host_url,
                                'storage_tiers',
                                tier.uuid,
                                bookmark=True)
        ]
        if expand:
            tier.istors = [
                link.Link.make_link('self', pecan.request.host_url,
                                    'storage_tiers', tier.uuid + "/istors"),
                link.Link.make_link('bookmark',
                                    pecan.request.host_url,
                                    'storage_tiers',
                                    tier.uuid + "/istors",
                                    bookmark=True)
            ]
        return tier