Bay to Cluster api cleanup

This patch fixes a few missed changes.  It also updates Cluster
and ClusterTemplate with a few changes that were merged while the
main patch was a WIP. Updates changes from patches:
Idd02769f98078702404a11dc9f7a3339ce4e22eb and
I1abc5626f39958351935f4c711c19588651d2bc6

Change-Id: I509520d1af0f0e2c04d53359705973d6a6f97a26
Implements: blueprint rename-bay-to-cluster
This commit is contained in:
Jaycen Grant 2016-08-22 12:56:58 -07:00
parent 52224c5c09
commit 4a3578101c
7 changed files with 88 additions and 67 deletions

View File

@ -96,7 +96,7 @@ def validate_fixed_network(cli, fixed_network):
"""Validate fixed network""" """Validate fixed network"""
# TODO(houming):this method implement will be added after this # TODO(houming):this method implement will be added after this
# first pathch for bay's OpenStack resources validation is merged. # first pathch for Cluster's OpenStack resources validation is merged.
pass pass
@ -166,21 +166,22 @@ def validate_labels_executor_env_variables(labels):
raise exception.InvalidParameterValue(err) raise exception.InvalidParameterValue(err)
def validate_os_resources(context, baymodel): def validate_os_resources(context, cluster_template):
"""Validate baymodel's OpenStack Resources""" """Validate ClusterTemplate's OpenStack Resources"""
cli = clients.OpenStackClients(context) cli = clients.OpenStackClients(context)
for attr, validate_method in validators.items(): for attr, validate_method in validators.items():
if attr in baymodel and baymodel[attr] is not None: if attr in cluster_template and cluster_template[attr] is not None:
if attr != 'labels': if attr != 'labels':
validate_method(cli, baymodel[attr]) validate_method(cli, cluster_template[attr])
else: else:
validate_method(baymodel[attr]) validate_method(cluster_template[attr])
def validate_master_count(bay, baymodel): def validate_master_count(cluster, cluster_template):
if bay['master_count'] > 1 and not baymodel['master_lb_enabled']: if cluster['master_count'] > 1 and \
not cluster_template['master_lb_enabled']:
raise exception.InvalidParameterValue(_( raise exception.InvalidParameterValue(_(
"master_count must be 1 when master_lb_enabled is False")) "master_count must be 1 when master_lb_enabled is False"))

View File

@ -142,12 +142,12 @@ class Controller(rest.RestController):
Example: Example:
@base.Controller.api_version("1.1", "1.2") @base.Controller.api_version("1.1", "1.2")
@expose.expose(Bay, types.uuid_or_name) @expose.expose(Cluster, types.uuid_or_name)
def get_one(self, bay_ident): def get_one(self, bay_ident):
{...code for versions 1.1 to 1.2...} {...code for versions 1.1 to 1.2...}
@base.Controller.api_version("1.3") @base.Controller.api_version("1.3")
@expose.expose(Bay, types.uuid_or_name) @expose.expose(Cluster, types.uuid_or_name)
def get_one(self, bay_ident): def get_one(self, bay_ident):
{...code for versions 1.3 to latest} {...code for versions 1.3 to latest}

View File

@ -52,7 +52,7 @@ class Link(base.APIBase):
@classmethod @classmethod
def sample(cls): def sample(cls):
sample = cls(href="http://localhost:9511/bays/" sample = cls(href="http://localhost:9511/clusters/"
"eaaca217-e7d8-47b4-bb41-3f99f20eed89", "eaaca217-e7d8-47b4-bb41-3f99f20eed89",
rel="bookmark") rel="bookmark")
return sample return sample

View File

@ -74,7 +74,7 @@ class Cluster(base.APIBase):
"""API representation of a cluster. """API representation of a cluster.
This class enforces type checking and value constraints, and converts This class enforces type checking and value constraints, and converts
between the internal object model and the API representation of a bay. between the internal object model and the API representation of a Cluster.
""" """
_cluster_template_id = None _cluster_template_id = None
@ -89,7 +89,7 @@ class Cluster(base.APIBase):
self._cluster_template_id = cluster_template.uuid self._cluster_template_id = cluster_template.uuid
except exception.ClusterTemplateNotFound as e: except exception.ClusterTemplateNotFound as e:
# Change error code because 404 (NotFound) is inappropriate # Change error code because 404 (NotFound) is inappropriate
# response for a POST request to create a Bay # response for a POST request to create a Cluster
e.code = 400 # BadRequest e.code = 400 # BadRequest
raise raise
elif value == wtypes.Unset: elif value == wtypes.Unset:
@ -194,8 +194,8 @@ class Cluster(base.APIBase):
return cluster return cluster
@classmethod @classmethod
def convert_with_links(cls, rpc_bay, expand=True): def convert_with_links(cls, rpc_cluster, expand=True):
cluster = Cluster(**rpc_bay.as_dict()) cluster = Cluster(**rpc_cluster.as_dict())
return cls._convert_with_links(cluster, pecan.request.host_url, expand) return cls._convert_with_links(cluster, pecan.request.host_url, expand)
@classmethod @classmethod
@ -247,10 +247,11 @@ class ClusterCollection(collection.Collection):
self._type = 'clusters' self._type = 'clusters'
@staticmethod @staticmethod
def convert_with_links(rpc_bays, limit, url=None, expand=False, **kwargs): def convert_with_links(rpc_clusters, limit, url=None, expand=False,
**kwargs):
collection = ClusterCollection() collection = ClusterCollection()
collection.clusters = [Cluster.convert_with_links(p, expand) collection.clusters = [Cluster.convert_with_links(p, expand)
for p in rpc_bays] for p in rpc_clusters]
collection.next = collection.get_next(limit, url=url, **kwargs) collection.next = collection.get_next(limit, url=url, **kwargs)
return collection return collection
@ -272,7 +273,7 @@ class ClustersController(base.Controller):
} }
def _generate_name_for_cluster(self, context): def _generate_name_for_cluster(self, context):
"""Generate a random name like: zeta-22-bay.""" """Generate a random name like: zeta-22-cluster."""
name_gen = name_generator.NameGenerator() name_gen = name_generator.NameGenerator()
name = name_gen.generate() name = name_gen.generate()
return name + '-cluster' return name + '-cluster'
@ -365,13 +366,13 @@ class ClustersController(base.Controller):
for res in failed_resources} for res in failed_resources}
@expose.expose(Cluster, types.uuid_or_name) @expose.expose(Cluster, types.uuid_or_name)
def get_one(self, bay_ident): def get_one(self, cluster_ident):
"""Retrieve information about the given bay. """Retrieve information about the given Cluster.
:param bay_ident: UUID of a bay or logical name of the bay. :param cluster_ident: UUID or logical name of the Cluster.
""" """
context = pecan.request.context context = pecan.request.context
cluster = api_utils.get_resource('Bay', bay_ident) cluster = api_utils.get_resource('Bay', cluster_ident)
policy.enforce(context, 'cluster:get', cluster, policy.enforce(context, 'cluster:get', cluster,
action='cluster:get') action='cluster:get')
@ -415,15 +416,36 @@ class ClustersController(base.Controller):
return ClusterID(new_cluster.uuid) return ClusterID(new_cluster.uuid)
@base.Controller.api_version("1.1", "1.2")
@wsme.validate(types.uuid, [ClusterPatchType]) @wsme.validate(types.uuid, [ClusterPatchType])
@expose.expose(ClusterID, types.uuid_or_name, body=[ClusterPatchType], @expose.expose(ClusterID, types.uuid_or_name, body=[ClusterPatchType],
status_code=202) status_code=202)
def patch(self, cluster_ident, patch): def patch(self, cluster_ident, patch):
"""Update an existing bay. """Update an existing Cluster.
:param cluster_ident: UUID or logical name of a bay. :param cluster_ident: UUID or logical name of a cluster.
:param patch: a json PATCH document to apply to this bay. :param patch: a json PATCH document to apply to this cluster.
""" """
cluster = self._patch(cluster_ident, patch)
pecan.request.rpcapi.bay_update_async(cluster)
return ClusterID(cluster.uuid)
@base.Controller.api_version("1.3") # noqa
@wsme.validate(types.uuid, bool, [ClusterPatchType])
@expose.expose(ClusterID, types.uuid_or_name, bool,
body=[ClusterPatchType], status_code=202)
def patch(self, cluster_ident, rollback=False, patch=None):
"""Update an existing Cluster.
:param cluster_ident: UUID or logical name of a cluster.
:param rollback: whether to rollback cluster on update failure.
:param patch: a json PATCH document to apply to this cluster.
"""
cluster = self._patch(cluster_ident, patch)
pecan.request.rpcapi.bay_update_async(cluster, rollback)
return ClusterID(cluster.uuid)
def _patch(self, cluster_ident, patch):
context = pecan.request.context context = pecan.request.context
cluster = api_utils.get_resource('Bay', cluster_ident) cluster = api_utils.get_resource('Bay', cluster_ident)
policy.enforce(context, 'cluster:update', cluster, policy.enforce(context, 'cluster:update', cluster,
@ -450,9 +472,7 @@ class ClustersController(base.Controller):
delta = cluster.obj_what_changed() delta = cluster.obj_what_changed()
validate_bay_properties(delta) validate_bay_properties(delta)
return cluster
pecan.request.rpcapi.bay_update_async(cluster)
return ClusterID(cluster.uuid)
@expose.expose(None, types.uuid_or_name, status_code=204) @expose.expose(None, types.uuid_or_name, status_code=204)
def delete(self, cluster_ident): def delete(self, cluster_ident):

View File

@ -43,31 +43,31 @@ class ClusterTemplatePatchType(types.JsonPatchType):
class ClusterTemplate(base.APIBase): class ClusterTemplate(base.APIBase):
"""API representation of a clustertemplate. """API representation of a ClusterTemplate.
This class enforces type checking and value constraints, and converts This class enforces type checking and value constraints, and converts
between the internal object model and the API representation of between the internal object model and the API representation of
a clustertemplate. a ClusterTemplate.
""" """
uuid = types.uuid uuid = types.uuid
"""Unique UUID for this clustertemplate""" """Unique UUID for this ClusterTemplate"""
name = wtypes.StringType(min_length=1, max_length=255) name = wtypes.StringType(min_length=1, max_length=255)
"""The name of the clustertemplate""" """The name of the ClusterTemplate"""
coe = wtypes.Enum(str, *fields.BayType.ALL, mandatory=True) coe = wtypes.Enum(str, *fields.BayType.ALL, mandatory=True)
"""The Container Orchestration Engine for this clustertemplate""" """The Container Orchestration Engine for this clustertemplate"""
image_id = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255), image_id = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255),
mandatory=True) mandatory=True)
"""The image name or UUID to use as an image for this clustertemplate""" """The image name or UUID to use as an image for this ClusterTemplate"""
flavor_id = wtypes.StringType(min_length=1, max_length=255) flavor_id = wtypes.StringType(min_length=1, max_length=255)
"""The flavor of this clustertemplate""" """The flavor of this ClusterTemplate"""
master_flavor_id = wtypes.StringType(min_length=1, max_length=255) master_flavor_id = wtypes.StringType(min_length=1, max_length=255)
"""The flavor of the master node for this clustertemplate""" """The flavor of the master node for this ClusterTemplate"""
dns_nameserver = wtypes.IPv4AddressType() dns_nameserver = wtypes.IPv4AddressType()
"""The DNS nameserver address""" """The DNS nameserver address"""
@ -77,13 +77,13 @@ class ClusterTemplate(base.APIBase):
"""The name or id of the nova ssh keypair""" """The name or id of the nova ssh keypair"""
external_network_id = wtypes.StringType(min_length=1, max_length=255) external_network_id = wtypes.StringType(min_length=1, max_length=255)
"""The external network to attach the cluster""" """The external network to attach to the Cluster"""
fixed_network = wtypes.StringType(min_length=1, max_length=255) fixed_network = wtypes.StringType(min_length=1, max_length=255)
"""The fixed network name to attach the cluster""" """The fixed network name to attach to the Cluster"""
fixed_subnet = wtypes.StringType(min_length=1, max_length=255) fixed_subnet = wtypes.StringType(min_length=1, max_length=255)
"""The fixed subnet name to attach the cluster""" """The fixed subnet name to attach to the Cluster"""
network_driver = wtypes.StringType(min_length=1, max_length=255) network_driver = wtypes.StringType(min_length=1, max_length=255)
"""The name of the driver used for instantiating container networks""" """The name of the driver used for instantiating container networks"""
@ -95,10 +95,10 @@ class ClusterTemplate(base.APIBase):
"""The size in GB of the docker volume""" """The size in GB of the docker volume"""
cluster_distro = wtypes.StringType(min_length=1, max_length=255) cluster_distro = wtypes.StringType(min_length=1, max_length=255)
"""The Cluster distro for the cluster, ex - coreos, fedora-atomic.""" """The Cluster distro for the Cluster, e.g. coreos, fedora-atomic, etc."""
links = wsme.wsattr([link.Link], readonly=True) links = wsme.wsattr([link.Link], readonly=True)
"""A list containing a self link and associated clustertemplate links""" """A list containing a self link and associated ClusterTemplate links"""
http_proxy = wtypes.StringType(min_length=1, max_length=255) http_proxy = wtypes.StringType(min_length=1, max_length=255)
"""Address of a proxy that will receive all HTTP requests and relay them. """Address of a proxy that will receive all HTTP requests and relay them.
@ -111,12 +111,12 @@ class ClusterTemplate(base.APIBase):
""" """
no_proxy = wtypes.StringType(min_length=1, max_length=255) no_proxy = wtypes.StringType(min_length=1, max_length=255)
"""A comma separated list of ips for which proxies should not """A comma separated list of IPs for which proxies should not be
used in the cluster used in the cluster
""" """
volume_driver = wtypes.StringType(min_length=1, max_length=255) volume_driver = wtypes.StringType(min_length=1, max_length=255)
"""The name of the driver used for instantiating container volume driver""" """The name of the driver used for instantiating container volumes"""
registry_enabled = wsme.wsattr(types.boolean, default=False) registry_enabled = wsme.wsattr(types.boolean, default=False)
"""Indicates whether the docker registry is enabled""" """Indicates whether the docker registry is enabled"""
@ -128,26 +128,26 @@ class ClusterTemplate(base.APIBase):
"""Indicates whether the TLS should be disabled""" """Indicates whether the TLS should be disabled"""
public = wsme.wsattr(types.boolean, default=False) public = wsme.wsattr(types.boolean, default=False)
"""Indicates whether the clustertemplate is public or not.""" """Indicates whether the ClusterTemplate is public or not."""
server_type = wsme.wsattr(wtypes.StringType(min_length=1, server_type = wsme.wsattr(wtypes.StringType(min_length=1,
max_length=255), max_length=255),
default='vm') default='vm')
"""Server type for this clustertemplate """ """Server type for this ClusterTemplate """
insecure_registry = wtypes.StringType(min_length=1, max_length=255) insecure_registry = wtypes.StringType(min_length=1, max_length=255)
"""insecure registry url when create clustertemplate """ """Insecure registry URL when creating a ClusterTemplate """
docker_storage_driver = wtypes.Enum(str, *fields.DockerStorageDriver.ALL) docker_storage_driver = wtypes.Enum(str, *fields.DockerStorageDriver.ALL)
"""Docker storage driver""" """Docker storage driver"""
master_lb_enabled = wsme.wsattr(types.boolean, default=False) master_lb_enabled = wsme.wsattr(types.boolean, default=False)
"""Indicates whether created bays should have a load balancer for master """Indicates whether created clusters should have a load balancer for master
nodes or not. nodes or not.
""" """
floating_ip_enabled = wsme.wsattr(types.boolean, default=True) floating_ip_enabled = wsme.wsattr(types.boolean, default=True)
"""Indicates whether created bays should have a floating ip or not.""" """Indicates whether created clusters should have a floating ip or not."""
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.fields = [] self.fields = []
@ -170,8 +170,8 @@ class ClusterTemplate(base.APIBase):
return cluster_template return cluster_template
@classmethod @classmethod
def convert_with_links(cls, rpc_baymodel): def convert_with_links(cls, rpc_cluster_template):
cluster_template = ClusterTemplate(**rpc_baymodel.as_dict()) cluster_template = ClusterTemplate(**rpc_cluster_template.as_dict())
return cls._convert_with_links(cluster_template, return cls._convert_with_links(cluster_template,
pecan.request.host_url) pecan.request.host_url)
@ -210,19 +210,19 @@ class ClusterTemplate(base.APIBase):
class ClusterTemplateCollection(collection.Collection): class ClusterTemplateCollection(collection.Collection):
"""API representation of a collection of clustertemplates.""" """API representation of a collection of ClusterTemplates."""
clustertemplates = [ClusterTemplate] clustertemplates = [ClusterTemplate]
"""A list containing clustertemplates objects""" """A list containing ClusterTemplates objects"""
def __init__(self, **kwargs): def __init__(self, **kwargs):
self._type = 'clustertemplates' self._type = 'clustertemplates'
@staticmethod @staticmethod
def convert_with_links(rpc_baymodels, limit, url=None, **kwargs): def convert_with_links(rpc_cluster_templates, limit, url=None, **kwargs):
collection = ClusterTemplateCollection() collection = ClusterTemplateCollection()
collection.clustertemplates = [ClusterTemplate.convert_with_links(p) collection.clustertemplates = [ClusterTemplate.convert_with_links(p)
for p in rpc_baymodels] for p in rpc_cluster_templates]
collection.next = collection.get_next(limit, url=url, **kwargs) collection.next = collection.get_next(limit, url=url, **kwargs)
return collection return collection
@ -274,7 +274,7 @@ class ClusterTemplatesController(base.Controller):
wtypes.text) wtypes.text)
def get_all(self, marker=None, limit=None, sort_key='id', def get_all(self, marker=None, limit=None, sort_key='id',
sort_dir='asc'): sort_dir='asc'):
"""Retrieve a list of baymodels. """Retrieve a list of ClusterTemplates.
:param marker: pagination marker for large data sets. :param marker: pagination marker for large data sets.
:param limit: maximum number of resources to return in a single result. :param limit: maximum number of resources to return in a single result.
@ -291,7 +291,7 @@ class ClusterTemplatesController(base.Controller):
wtypes.text) wtypes.text)
def detail(self, marker=None, limit=None, sort_key='id', def detail(self, marker=None, limit=None, sort_key='id',
sort_dir='asc'): sort_dir='asc'):
"""Retrieve a list of clustertemplates with detail. """Retrieve a list of ClusterTemplates with detail.
:param marker: pagination marker for large data sets. :param marker: pagination marker for large data sets.
:param limit: maximum number of resources to return in a single result. :param limit: maximum number of resources to return in a single result.
@ -314,10 +314,10 @@ class ClusterTemplatesController(base.Controller):
@expose.expose(ClusterTemplate, types.uuid_or_name) @expose.expose(ClusterTemplate, types.uuid_or_name)
def get_one(self, cluster_template_ident): def get_one(self, cluster_template_ident):
"""Retrieve information about the given clustertemplate. """Retrieve information about the given ClusterTemplate.
:param cluster_template_ident: UUID or logical name of a :param cluster_template_ident: UUID or logical name of a
clustertemplate. ClusterTemplate.
""" """
context = pecan.request.context context = pecan.request.context
cluster_template = api_utils.get_resource('BayModel', cluster_template = api_utils.get_resource('BayModel',
@ -333,9 +333,9 @@ class ClusterTemplatesController(base.Controller):
@validation.enforce_volume_driver_types_create() @validation.enforce_volume_driver_types_create()
@validation.enforce_volume_storage_size_create() @validation.enforce_volume_storage_size_create()
def post(self, cluster_template): def post(self, cluster_template):
"""Create a new cluster_template. """Create a new ClusterTemplate.
:param cluster_template: a cluster_template within the request body. :param cluster_template: a ClusterTemplate within the request body.
""" """
context = pecan.request.context context = pecan.request.context
policy.enforce(context, 'clustertemplate:create', policy.enforce(context, 'clustertemplate:create',
@ -375,12 +375,12 @@ class ClusterTemplatesController(base.Controller):
@validation.enforce_network_driver_types_update() @validation.enforce_network_driver_types_update()
@validation.enforce_volume_driver_types_update() @validation.enforce_volume_driver_types_update()
def patch(self, cluster_template_ident, patch): def patch(self, cluster_template_ident, patch):
"""Update an existing cluster_template. """Update an existing ClusterTemplate.
:param cluster_template_ident: UUID or logic name of a :param cluster_template_ident: UUID or logic name of a
cluster_template. ClusterTemplate.
:param patch: a json PATCH document to apply to this :param patch: a json PATCH document to apply to this
cluster_template. ClusterTemplate.
""" """
context = pecan.request.context context = pecan.request.context
cluster_template = api_utils.get_resource('BayModel', cluster_template = api_utils.get_resource('BayModel',
@ -398,7 +398,7 @@ class ClusterTemplatesController(base.Controller):
new_cluster_template_dict = new_cluster_template.as_dict() new_cluster_template_dict = new_cluster_template.as_dict()
attr_validator.validate_os_resources(context, attr_validator.validate_os_resources(context,
new_cluster_template_dict) new_cluster_template_dict)
# check permissions when updating baymodel public flag # check permissions when updating ClusterTemplate public flag
if cluster_template.public != new_cluster_template.public: if cluster_template.public != new_cluster_template.public:
if not policy.enforce(context, "clustertemplate:publish", None, if not policy.enforce(context, "clustertemplate:publish", None,
do_raise=False): do_raise=False):
@ -421,10 +421,10 @@ class ClusterTemplatesController(base.Controller):
@expose.expose(None, types.uuid_or_name, status_code=204) @expose.expose(None, types.uuid_or_name, status_code=204)
def delete(self, cluster_template_ident): def delete(self, cluster_template_ident):
"""Delete a cluster_template. """Delete a ClusterTemplate.
:param cluster_template_ident: UUID or logical name of a :param cluster_template_ident: UUID or logical name of a
cluster_template. ClusterTemplate.
""" """
context = pecan.request.context context = pecan.request.context
cluster_template = api_utils.get_resource('BayModel', cluster_template = api_utils.get_resource('BayModel',

View File

@ -59,7 +59,7 @@ class MagnumService(base.APIBase):
class MagnumServiceCollection(collection.Collection): class MagnumServiceCollection(collection.Collection):
mservices = [MagnumService] mservices = [MagnumService]
"""A list containing bays objects""" """A list containing service objects"""
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(MagnumServiceCollection, self).__init__() super(MagnumServiceCollection, self).__init__()

View File

@ -227,7 +227,7 @@ class TestPatch(api_base.FunctionalTest):
self.mock_bay_update.side_effect = self._simulate_rpc_bay_update self.mock_bay_update.side_effect = self._simulate_rpc_bay_update
self.addCleanup(p.stop) self.addCleanup(p.stop)
def _simulate_rpc_bay_update(self, bay): def _simulate_rpc_bay_update(self, bay, rollback=False):
bay.save() bay.save()
return bay return bay