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
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
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
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)
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)
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()
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