def test_invalid_values(self): vt = types.MultiType(wsme.types.text, six.integer_types) self.assertRaises(ValueError, vt.validate, 0.10) self.assertRaises(ValueError, vt.validate, object()) vt = types.MultiType(types.UuidType, six.integer_types) self.assertRaises(ValueError, vt.validate, 'abc') self.assertRaises(ValueError, vt.validate, 0.10)
def test_valid_values(self): vt = types.MultiType(wsme.types.text, six.integer_types) value = vt.validate("hello") self.assertEqual("hello", value) value = vt.validate(10) self.assertEqual(10, value) vt = types.MultiType(types.UuidType, types.NameType) value = vt.validate('name') self.assertEqual('name', value) uuid = "437319e3-d10f-49ec-84c8-e4abb6118c29" value = vt.validate(uuid) self.assertEqual(uuid, value) vt = types.MultiType(types.UuidType, six.integer_types) value = vt.validate(10) self.assertEqual(10, value) value = vt.validate(uuid) self.assertEqual(uuid, value)
class NodeGroup(base.APIBase): """API representation of a Node group. This class enforces type checking and value constraints, and converts between the internal object model and the API representation of NodeGroup. """ id = wsme.wsattr(wtypes.IntegerType(minimum=1)) """unique id""" uuid = types.uuid """Unique UUID for this nodegroup""" name = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255), default=None) """Name of this nodegroup""" cluster_id = types.uuid """Unique UUID for the cluster where the nodegroup belongs to""" project_id = wsme.wsattr(wtypes.text, readonly=True) """Project UUID for this nodegroup""" docker_volume_size = wtypes.IntegerType(minimum=1) """The size in GB of the docker volume""" labels = wtypes.DictType(wtypes.text, types.MultiType(wtypes.text, six.integer_types, bool, float)) """One or more key/value pairs""" links = wsme.wsattr([link.Link], readonly=True) """A list containing a self link and associated nodegroup links""" flavor_id = wtypes.StringType(min_length=1, max_length=255) """The flavor of this nodegroup""" image_id = wtypes.StringType(min_length=1, max_length=255) """The image used for this nodegroup""" node_addresses = wsme.wsattr([wtypes.text], readonly=True) """IP addresses of nodegroup nodes""" node_count = wsme.wsattr(wtypes.IntegerType(minimum=1), default=1) """The node count for this nodegroup. Default to 1 if not set""" role = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255), default='worker') """The role of the nodes included in this nodegroup""" min_node_count = wsme.wsattr(wtypes.IntegerType(minimum=1), default=1) """The minimum allowed nodes for this nodegroup. Default to 1 if not set""" max_node_count = wsme.wsattr(wtypes.IntegerType(minimum=1), default=None) """The maximum allowed nodes for this nodegroup. Default to 1 if not set""" is_default = types.BooleanType() """Specifies is a nodegroup was created by default or not""" stack_id = wsme.wsattr(wtypes.text, readonly=True) """Stack id of the heat stack""" status = wtypes.Enum(wtypes.text, *fields.ClusterStatus.ALL) """Status of the nodegroup from the heat stack""" status_reason = wtypes.text """Status reason of the nodegroup from the heat stack""" version = wtypes.text """Version of the nodegroup""" merge_labels = wsme.wsattr(types.boolean, default=False) """Indicates whether the labels will be merged with the cluster labels.""" labels_overridden = wtypes.DictType( wtypes.text, types.MultiType( wtypes.text, six.integer_types, bool, float)) """Contains labels that have a value different than the parent labels.""" labels_added = wtypes.DictType( wtypes.text, types.MultiType( wtypes.text, six.integer_types, bool, float)) """Contains labels that do not exist in the parent.""" labels_skipped = wtypes.DictType( wtypes.text, types.MultiType( wtypes.text, six.integer_types, bool, float)) """Contains labels that exist in the parent but were not inherited.""" def __init__(self, **kwargs): super(NodeGroup, self).__init__() self.fields = [] for field in objects.NodeGroup.fields: # Skip fields we do not expose. if not hasattr(self, field): continue self.fields.append(field) setattr(self, field, kwargs.get(field, wtypes.Unset)) @classmethod def convert(cls, nodegroup, expand=True): url = pecan.request.host_url cluster_path = 'clusters/%s' % nodegroup.cluster_id nodegroup_path = 'nodegroups/%s' % nodegroup.uuid ng = NodeGroup(**nodegroup.as_dict()) if not expand: ng.unset_fields_except(["uuid", "name", "flavor_id", "node_count", "role", "is_default", "image_id", "status", "stack_id"]) else: ng.links = [link.Link.make_link('self', url, cluster_path, nodegroup_path), link.Link.make_link('bookmark', url, cluster_path, nodegroup_path, bookmark=True)] cluster = api_utils.get_resource('Cluster', ng.cluster_id) overridden, added, skipped = api_utils.get_labels_diff( cluster.labels, ng.labels) ng.labels_overridden = overridden ng.labels_added = added ng.labels_skipped = skipped return ng
class Bay(base.APIBase): """API representation of a bay. This class enforces type checking and value constraints, and converts between the internal object model and the API representation of a bay. """ _baymodel_id = None def _get_baymodel_id(self): return self._baymodel_id def _set_baymodel_id(self, value): if value and self._baymodel_id != value: try: baymodel = api_utils.get_resource('ClusterTemplate', value) self._baymodel_id = baymodel.uuid except exception.ClusterTemplateNotFound as e: # Change error code because 404 (NotFound) is inappropriate # response for a POST request to create a Cluster e.code = 400 # BadRequest raise elif value == wtypes.Unset: self._baymodel_id = wtypes.Unset uuid = types.uuid """Unique UUID for this bay""" name = wtypes.StringType(min_length=1, max_length=242, pattern='^[a-zA-Z][a-zA-Z0-9_.-]*$') """Name of this bay, max length is limited to 242 because of heat stack requires max length limit to 255, and Magnum amend a uuid length""" baymodel_id = wsme.wsproperty(wtypes.text, _get_baymodel_id, _set_baymodel_id, mandatory=True) """The baymodel UUID""" node_count = wsme.wsattr(wtypes.IntegerType(minimum=1), default=1) """The node count for this bay. Default to 1 if not set""" master_count = wsme.wsattr(wtypes.IntegerType(minimum=1), default=1) """The number of master nodes for this bay. Default to 1 if not set""" docker_volume_size = wtypes.IntegerType(minimum=1) """The size in GB of the docker volume""" labels = wtypes.DictType( wtypes.text, types.MultiType(wtypes.text, six.integer_types, bool, float)) """One or more key/value pairs""" master_flavor_id = wtypes.StringType(min_length=1, max_length=255) """The master flavor of this Bay""" flavor_id = wtypes.StringType(min_length=1, max_length=255) """The flavor of this Bay""" bay_create_timeout = wsme.wsattr(wtypes.IntegerType(minimum=0), default=60) """Timeout for creating the bay in minutes. Default to 60 if not set""" links = wsme.wsattr([link.Link], readonly=True) """A list containing a self link and associated bay links""" stack_id = wsme.wsattr(wtypes.text, readonly=True) """Stack id of the heat stack""" status = wtypes.Enum(wtypes.text, *fields.ClusterStatus.ALL) """Status of the bay from the heat stack""" status_reason = wtypes.text """Status reason of the bay from the heat stack""" discovery_url = wtypes.text """Url used for bay node discovery""" api_address = wsme.wsattr(wtypes.text, readonly=True) """Api address of cluster master node""" coe_version = wsme.wsattr(wtypes.text, readonly=True) """Version of the COE software currently running in this cluster. Example: swarm version or kubernetes version.""" container_version = wsme.wsattr(wtypes.text, readonly=True) """Version of the container software. Example: docker version.""" node_addresses = wsme.wsattr([wtypes.text], readonly=True) """IP addresses of cluster slave nodes""" master_addresses = wsme.wsattr([wtypes.text], readonly=True) """IP addresses of cluster master nodes""" bay_faults = wsme.wsattr(wtypes.DictType(wtypes.text, wtypes.text)) """Fault info collected from the heat resources of this bay""" def __init__(self, **kwargs): super(Bay, self).__init__() self.fields = [] for field in objects.Cluster.fields: # Skip fields we do not expose. if not hasattr(self, field): continue self.fields.append(field) setattr(self, field, kwargs.get(field, wtypes.Unset)) # Set the renamed attributes for bay backwards compatibility self.fields.append('baymodel_id') if 'baymodel_id' in kwargs.keys(): setattr(self, 'cluster_template_id', kwargs.get('baymodel_id', None)) setattr(self, 'baymodel_id', kwargs.get('baymodel_id', None)) else: setattr(self, 'baymodel_id', kwargs.get('cluster_template_id', None)) self.fields.append('bay_create_timeout') if 'bay_create_timeout' in kwargs.keys(): setattr(self, 'create_timeout', kwargs.get('bay_create_timeout', wtypes.Unset)) setattr(self, 'bay_create_timeout', kwargs.get('bay_create_timeout', wtypes.Unset)) else: setattr(self, 'bay_create_timeout', kwargs.get('create_timeout', wtypes.Unset)) self.fields.append('bay_faults') if 'bay_faults' in kwargs.keys(): setattr(self, 'faults', kwargs.get('bay_faults', wtypes.Unset)) setattr(self, 'bay_faults', kwargs.get('bay_faults', wtypes.Unset)) else: setattr(self, 'bay_faults', kwargs.get('faults', wtypes.Unset)) @staticmethod def _convert_with_links(bay, url, expand=True): if not expand: bay.unset_fields_except([ 'uuid', 'name', 'baymodel_id', 'docker_volume_size', 'labels', 'master_flavor_id', 'flavor_id', 'node_count', 'status', 'bay_create_timeout', 'master_count', 'stack_id' ]) bay.links = [ link.Link.make_link('self', url, 'bays', bay.uuid), link.Link.make_link('bookmark', url, 'bays', bay.uuid, bookmark=True) ] return bay @classmethod def convert_with_links(cls, rpc_bay, expand=True): bay = Bay(**rpc_bay.as_dict()) return cls._convert_with_links(bay, pecan.request.host_url, expand) @classmethod def sample(cls, expand=True): sample = cls(uuid='27e3153e-d5bf-4b7e-b517-fb518e17f34c', name='example', baymodel_id='4a96ac4b-2447-43f1-8ca6-9fd6f36d146d', node_count=2, master_count=1, docker_volume_size=1, labels={}, master_flavor_id=None, flavor_id=None, bay_create_timeout=15, stack_id='49dc23f5-ffc9-40c3-9d34-7be7f9e34d63', status=fields.ClusterStatus.CREATE_COMPLETE, status_reason="CREATE completed successfully", api_address='172.24.4.3', node_addresses=['172.24.4.4', '172.24.4.5'], created_at=timeutils.utcnow(), updated_at=timeutils.utcnow(), coe_version=None, container_version=None) return cls._convert_with_links(sample, 'http://localhost:9511', expand) def as_dict(self): """Render this object as a dict of its fields.""" # Override this for old bay values d = super(Bay, self).as_dict() d['cluster_template_id'] = d['baymodel_id'] del d['baymodel_id'] d['create_timeout'] = d['bay_create_timeout'] del d['bay_create_timeout'] if 'bay_faults' in d.keys(): d['faults'] = d['bay_faults'] del d['bay_faults'] return d
class ClusterTemplate(base.APIBase): """API representation of a ClusterTemplate. This class enforces type checking and value constraints, and converts between the internal object model and the API representation of a ClusterTemplate. """ uuid = types.uuid """Unique UUID for this ClusterTemplate""" name = wtypes.StringType(min_length=1, max_length=255) """The name of the ClusterTemplate""" coe = wtypes.Enum(wtypes.text, *fields.ClusterType.ALL, mandatory=True) """The Container Orchestration Engine for this clustertemplate""" image_id = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255), mandatory=True) """The image name or UUID to use as an image for this ClusterTemplate""" flavor_id = wtypes.StringType(min_length=1, max_length=255) """The flavor of this ClusterTemplate""" master_flavor_id = wtypes.StringType(min_length=1, max_length=255) """The flavor of the master node for this ClusterTemplate""" dns_nameserver = wtypes.IPv4AddressType() """The DNS nameserver address""" keypair_id = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255), default=None) """The name of the nova ssh keypair""" external_network_id = wtypes.StringType(min_length=1, max_length=255) """The external network to attach to the Cluster""" fixed_network = wtypes.StringType(min_length=1, max_length=255) """The fixed network name to attach to the Cluster""" fixed_subnet = wtypes.StringType(min_length=1, max_length=255) """The fixed subnet name to attach to the Cluster""" network_driver = wtypes.StringType(min_length=1, max_length=255) """The name of the driver used for instantiating container networks""" apiserver_port = wtypes.IntegerType(minimum=1024, maximum=65535) """The API server port for k8s""" docker_volume_size = wtypes.IntegerType(minimum=1) """The size in GB of the docker volume""" cluster_distro = wtypes.StringType(min_length=1, max_length=255) """The Cluster distro for the Cluster, e.g. coreos, fedora-atomic, etc.""" links = wsme.wsattr([link.Link], readonly=True) """A list containing a self link and associated ClusterTemplate links""" http_proxy = wtypes.StringType(min_length=1, max_length=255) """Address of a proxy that will receive all HTTP requests and relay them. The format is a URL including a port number. """ https_proxy = wtypes.StringType(min_length=1, max_length=255) """Address of a proxy that will receive all HTTPS requests and relay them. The format is a URL including a port number. """ no_proxy = wtypes.StringType(min_length=1, max_length=255) """A comma separated list of IPs for which proxies should not be used in the cluster """ volume_driver = wtypes.StringType(min_length=1, max_length=255) """The name of the driver used for instantiating container volumes""" registry_enabled = wsme.wsattr(types.boolean, default=False) """Indicates whether the docker registry is enabled""" labels = wtypes.DictType( wtypes.text, types.MultiType(wtypes.text, six.integer_types, bool, float)) """One or more key/value pairs""" tls_disabled = wsme.wsattr(types.boolean, default=False) """Indicates whether the TLS should be disabled""" public = wsme.wsattr(types.boolean, default=False) """Indicates whether the ClusterTemplate is public or not.""" server_type = wsme.wsattr(wtypes.Enum(wtypes.text, *fields.ServerType.ALL), default='vm') """Server type for this ClusterTemplate """ insecure_registry = wtypes.StringType(min_length=1, max_length=255) """Insecure registry URL when creating a ClusterTemplate """ docker_storage_driver = wtypes.StringType(min_length=1, max_length=255) """Docker storage driver""" master_lb_enabled = wsme.wsattr(types.boolean, default=False) """Indicates whether created clusters should have a load balancer for master nodes or not. """ floating_ip_enabled = wsme.wsattr(types.boolean, default=True) """Indicates whether created clusters should have a floating ip or not.""" project_id = wsme.wsattr(wtypes.text, readonly=True) """Project id of the cluster belongs to""" user_id = wsme.wsattr(wtypes.text, readonly=True) """User id of the cluster belongs to""" hidden = wsme.wsattr(types.boolean, default=False) """Indicates whether the ClusterTemplate is hidden or not.""" def __init__(self, **kwargs): self.fields = [] for field in objects.ClusterTemplate.fields: # Skip fields we do not expose. if not hasattr(self, field): continue self.fields.append(field) setattr(self, field, kwargs.get(field, wtypes.Unset)) @staticmethod def _convert_with_links(cluster_template, url): cluster_template.links = [ link.Link.make_link('self', url, 'clustertemplates', cluster_template.uuid), link.Link.make_link('bookmark', url, 'clustertemplates', cluster_template.uuid, bookmark=True) ] return cluster_template @classmethod def convert_with_links(cls, rpc_cluster_template): cluster_template = ClusterTemplate(**rpc_cluster_template.as_dict()) return cls._convert_with_links(cluster_template, pecan.request.host_url) @classmethod def sample(cls): sample = cls( uuid='27e3153e-d5bf-4b7e-b517-fb518e17f34c', name='example', image_id='Fedora-k8s', flavor_id='m1.small', master_flavor_id='m1.small', dns_nameserver='8.8.1.1', keypair_id='keypair1', external_network_id='ffc44e4a-2319-4062-bce0-9ae1c38b05ba', fixed_network='private', fixed_subnet='private-subnet', network_driver='libnetwork', volume_driver='cinder', apiserver_port=8080, docker_volume_size=25, docker_storage_driver='devicemapper', cluster_distro='fedora-atomic', coe=fields.ClusterType.KUBERNETES, http_proxy='http://proxy.com:123', https_proxy='https://proxy.com:123', no_proxy='192.168.0.1,192.168.0.2,192.168.0.3', labels={ 'key1': 'val1', 'key2': 'val2' }, server_type='vm', insecure_registry='10.238.100.100:5000', created_at=timeutils.utcnow(), updated_at=timeutils.utcnow(), public=False, master_lb_enabled=False, floating_ip_enabled=True, hidden=False) return cls._convert_with_links(sample, 'http://localhost:9511')
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. """ _cluster_template_id = None def _get_cluster_template_id(self): return self._cluster_template_id def _set_cluster_template_id(self, value): if value and self._cluster_template_id != value: try: cluster_template = api_utils.get_resource('ClusterTemplate', value) self._cluster_template_id = cluster_template.uuid except exception.ClusterTemplateNotFound as e: # Change error code because 404 (NotFound) is inappropriate # response for a POST request to create a Cluster e.code = 400 # BadRequest raise elif value == wtypes.Unset: self._cluster_template_id = wtypes.Unset uuid = types.uuid """Unique UUID for this cluster""" name = wtypes.StringType(min_length=1, max_length=242, pattern='^[a-zA-Z][a-zA-Z0-9_.-]*$') """Name of this cluster, max length is limited to 242 because of heat stack requires max length limit to 255, and Magnum amend a uuid length""" cluster_template_id = wsme.wsproperty(wtypes.text, _get_cluster_template_id, _set_cluster_template_id, mandatory=True) """The cluster_template UUID""" keypair = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255), default=None) """The name of the nova ssh keypair""" node_count = wsme.wsattr(wtypes.IntegerType(minimum=1), default=1) """The node count for this cluster. Default to 1 if not set""" master_count = wsme.wsattr(wtypes.IntegerType(minimum=1), default=1) """The number of master nodes for this cluster. Default to 1 if not set""" docker_volume_size = wtypes.IntegerType(minimum=1) """The size in GB of the docker volume""" labels = wtypes.DictType(wtypes.text, types.MultiType(wtypes.text, six.integer_types, bool, float)) """One or more key/value pairs""" master_flavor_id = wtypes.StringType(min_length=1, max_length=255) """The flavor of the master node for this Cluster""" flavor_id = wtypes.StringType(min_length=1, max_length=255) """The flavor of this Cluster""" create_timeout = wsme.wsattr(wtypes.IntegerType(minimum=0), default=60) """Timeout for creating the cluster in minutes. Default to 60 if not set""" links = wsme.wsattr([link.Link], readonly=True) """A list containing a self link and associated cluster links""" stack_id = wsme.wsattr(wtypes.text, readonly=True) """Stack id of the heat stack""" status = wtypes.Enum(wtypes.text, *fields.ClusterStatus.ALL) """Status of the cluster from the heat stack""" status_reason = wtypes.text """Status reason of the cluster from the heat stack""" health_status = wtypes.Enum(wtypes.text, *fields.ClusterStatus.ALL) """Health status of the cluster from the native COE API""" health_status_reason = wtypes.DictType(wtypes.text, wtypes.text) """Health status reason of the cluster from the native COE API""" discovery_url = wtypes.text """Url used for cluster node discovery""" api_address = wsme.wsattr(wtypes.text, readonly=True) """Api address of cluster master node""" coe_version = wsme.wsattr(wtypes.text, readonly=True) """Version of the COE software currently running in this cluster. Example: swarm version or kubernetes version.""" container_version = wsme.wsattr(wtypes.text, readonly=True) """Version of the container software. Example: docker version.""" project_id = wsme.wsattr(wtypes.text, readonly=True) """Project id of the cluster belongs to""" user_id = wsme.wsattr(wtypes.text, readonly=True) """User id of the cluster belongs to""" node_addresses = wsme.wsattr([wtypes.text], readonly=True) """IP addresses of cluster slave nodes""" master_addresses = wsme.wsattr([wtypes.text], readonly=True) """IP addresses of cluster master nodes""" faults = wsme.wsattr(wtypes.DictType(wtypes.text, wtypes.text)) """Fault info collected from the heat resources of this cluster""" def __init__(self, **kwargs): super(Cluster, self).__init__() self.fields = [] for field in objects.Cluster.fields: # Skip fields we do not expose. if not hasattr(self, field): continue self.fields.append(field) setattr(self, field, kwargs.get(field, wtypes.Unset)) @staticmethod def _convert_with_links(cluster, url, expand=True): if not expand: cluster.unset_fields_except(['uuid', 'name', 'cluster_template_id', 'keypair', 'docker_volume_size', 'labels', 'node_count', 'status', 'master_flavor_id', 'flavor_id', 'create_timeout', 'master_count', 'stack_id']) cluster.links = [link.Link.make_link('self', url, 'clusters', cluster.uuid), link.Link.make_link('bookmark', url, 'clusters', cluster.uuid, bookmark=True)] return cluster @classmethod def convert_with_links(cls, rpc_cluster, expand=True): cluster = Cluster(**rpc_cluster.as_dict()) return cls._convert_with_links(cluster, pecan.request.host_url, expand) @classmethod def sample(cls, expand=True): temp_id = '4a96ac4b-2447-43f1-8ca6-9fd6f36d146d' sample = cls(uuid='27e3153e-d5bf-4b7e-b517-fb518e17f34c', name='example', cluster_template_id=temp_id, keypair=None, node_count=2, master_count=1, docker_volume_size=1, labels={}, master_flavor_id='m1.small', flavor_id='m1.small', create_timeout=15, stack_id='49dc23f5-ffc9-40c3-9d34-7be7f9e34d63', status=fields.ClusterStatus.CREATE_COMPLETE, status_reason="CREATE completed successfully", health_status=fields.ClusterHealthStatus.HEALTHY, health_status_reason='{"api_server": "OK"}', api_address='172.24.4.3', node_addresses=['172.24.4.4', '172.24.4.5'], created_at=timeutils.utcnow(), updated_at=timeutils.utcnow(), coe_version=None, container_version=None) return cls._convert_with_links(sample, 'http://localhost:9511', expand)
def test_multitype_tostring(self): vt = types.MultiType(str, int) vts = str(vt) self.assertIn(str(str), vts) self.assertIn(str(int), vts)
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. """ uuid = types.uuid """Unique UUID for this cluster""" name = wtypes.StringType(min_length=1, max_length=242, pattern='^[a-zA-Z][a-zA-Z0-9_.-]*$') """Name of this cluster, max length is limited to 242 because of heat stack requires max length limit to 255, and Magnum amend a uuid length""" cluster_template_id = wsme.wsattr(wtypes.text, mandatory=True) """The cluster_template UUID""" keypair = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255), default=None) """The name of the nova ssh keypair""" node_count = wsme.wsattr(wtypes.IntegerType(minimum=0), default=1) """The node count for this cluster. Default to 1 if not set""" master_count = wsme.wsattr(wtypes.IntegerType(minimum=1), default=1) """The number of master nodes for this cluster. Default to 1 if not set""" docker_volume_size = wtypes.IntegerType(minimum=1) """The size in GB of the docker volume""" labels = wtypes.DictType( wtypes.text, types.MultiType(wtypes.text, six.integer_types, bool, float)) """One or more key/value pairs""" master_flavor_id = wtypes.StringType(min_length=1, max_length=255) """The flavor of the master node for this Cluster""" flavor_id = wtypes.StringType(min_length=1, max_length=255) """The flavor of this Cluster""" create_timeout = wsme.wsattr(wtypes.IntegerType(minimum=0), default=60) """Timeout for creating the cluster in minutes. Default to 60 if not set""" links = wsme.wsattr([link.Link], readonly=True) """A list containing a self link and associated cluster links""" stack_id = wsme.wsattr(wtypes.text, readonly=True) """Stack id of the heat stack""" status = wtypes.Enum(wtypes.text, *fields.ClusterStatus.ALL) """Status of the cluster from the heat stack""" status_reason = wtypes.text """Status reason of the cluster from the heat stack""" health_status = wtypes.Enum(wtypes.text, *fields.ClusterHealthStatus.ALL) """Health status of the cluster from the native COE API""" health_status_reason = wtypes.DictType(wtypes.text, wtypes.text) """Health status reason of the cluster from the native COE API""" discovery_url = wtypes.text """Url used for cluster node discovery""" api_address = wsme.wsattr(wtypes.text, readonly=True) """Api address of cluster master node""" coe_version = wsme.wsattr(wtypes.text, readonly=True) """Version of the COE software currently running in this cluster. Example: swarm version or kubernetes version.""" container_version = wsme.wsattr(wtypes.text, readonly=True) """Version of the container software. Example: docker version.""" project_id = wsme.wsattr(wtypes.text, readonly=True) """Project id of the cluster belongs to""" user_id = wsme.wsattr(wtypes.text, readonly=True) """User id of the cluster belongs to""" node_addresses = wsme.wsattr([wtypes.text], readonly=True) """IP addresses of cluster slave nodes""" master_addresses = wsme.wsattr([wtypes.text], readonly=True) """IP addresses of cluster master nodes""" faults = wsme.wsattr(wtypes.DictType(wtypes.text, wtypes.text)) """Fault info collected from the heat resources of this cluster""" fixed_network = wtypes.StringType(min_length=1, max_length=255) """The fixed network name to attach to the Cluster""" fixed_subnet = wtypes.StringType(min_length=1, max_length=255) """The fixed subnet name to attach to the Cluster""" floating_ip_enabled = wsme.wsattr(types.boolean) """Indicates whether created clusters should have a floating ip or not.""" merge_labels = wsme.wsattr(types.boolean, default=False) """Indicates whether the labels will be merged with the CT labels.""" labels_overridden = wtypes.DictType( wtypes.text, types.MultiType(wtypes.text, six.integer_types, bool, float)) """Contains labels that have a value different than the parent labels.""" labels_added = wtypes.DictType( wtypes.text, types.MultiType(wtypes.text, six.integer_types, bool, float)) """Contains labels that do not exist in the parent.""" labels_skipped = wtypes.DictType( wtypes.text, types.MultiType(wtypes.text, six.integer_types, bool, float)) """Contains labels that exist in the parent but were not inherited.""" master_lb_enabled = wsme.wsattr(types.boolean) """Indicates whether created clusters should have a load balancer for master nodes or not. """ def __init__(self, **kwargs): super(Cluster, self).__init__() self.fields = [] for field in objects.Cluster.fields: # Skip fields we do not expose. if not hasattr(self, field): continue self.fields.append(field) setattr(self, field, kwargs.get(field, wtypes.Unset)) nodegroup_fields = [ 'node_count', 'master_count', 'node_addresses', 'master_addresses' ] for field in nodegroup_fields: self.fields.append(field) setattr(self, field, kwargs.get(field, wtypes.Unset)) @staticmethod def _convert_with_links(cluster, url, expand=True, parent_labels=None): if not expand: cluster.unset_fields_except([ 'uuid', 'name', 'cluster_template_id', 'keypair', 'docker_volume_size', 'labels', 'node_count', 'status', 'master_flavor_id', 'flavor_id', 'create_timeout', 'master_count', 'stack_id', 'health_status' ]) else: overridden, added, skipped = api_utils.get_labels_diff( parent_labels, cluster.labels) cluster.labels_overridden = overridden cluster.labels_added = added cluster.labels_skipped = skipped cluster.links = [ link.Link.make_link('self', url, 'clusters', cluster.uuid), link.Link.make_link('bookmark', url, 'clusters', cluster.uuid, bookmark=True) ] return cluster @classmethod def convert_with_links(cls, rpc_cluster, expand=True): cluster = Cluster(**rpc_cluster.as_dict()) parent_labels = rpc_cluster.cluster_template.labels return cls._convert_with_links(cluster, pecan.request.host_url, expand, parent_labels) @classmethod def sample(cls, expand=True): temp_id = '4a96ac4b-2447-43f1-8ca6-9fd6f36d146d' sample = cls(uuid='27e3153e-d5bf-4b7e-b517-fb518e17f34c', name='example', cluster_template_id=temp_id, keypair=None, node_count=2, master_count=1, docker_volume_size=1, labels={}, master_flavor_id='m1.small', flavor_id='m1.small', create_timeout=15, stack_id='49dc23f5-ffc9-40c3-9d34-7be7f9e34d63', status=fields.ClusterStatus.CREATE_COMPLETE, status_reason="CREATE completed successfully", health_status=fields.ClusterHealthStatus.HEALTHY, health_status_reason={ "api": "ok", "node-0.Ready": 'True' }, api_address='172.24.4.3', node_addresses=['172.24.4.4', '172.24.4.5'], created_at=timeutils.utcnow(), updated_at=timeutils.utcnow(), coe_version=None, container_version=None, fixed_network=None, fixed_subnet=None, floating_ip_enabled=True, master_lb_enabled=True) return cls._convert_with_links(sample, 'http://localhost:9511', expand)