Beispiel #1
0
    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)
Beispiel #2
0
    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)
Beispiel #3
0
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
Beispiel #4
0
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')
Beispiel #6
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.
    """

    _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)
Beispiel #7
0
 def test_multitype_tostring(self):
     vt = types.MultiType(str, int)
     vts = str(vt)
     self.assertIn(str(str), vts)
     self.assertIn(str(int), vts)
Beispiel #8
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.
    """

    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)