Browse Source

Merge "Rename Bay DB, Object, and internal usage to Cluster"

changes/60/314060/15
Jenkins 5 years ago
committed by Gerrit Code Review
parent
commit
4548b310e5
  1. 4
      magnum/api/controllers/base.py
  2. 99
      magnum/api/controllers/v1/bay.py
  3. 4
      magnum/api/controllers/v1/baymodel.py
  4. 9
      magnum/api/controllers/v1/certificate.py
  5. 89
      magnum/api/controllers/v1/cluster.py
  6. 4
      magnum/api/controllers/v1/cluster_template.py
  7. 39
      magnum/api/validation.py
  8. 4
      magnum/cmd/conductor.py
  9. 6
      magnum/cmd/template_manage.py
  10. 12
      magnum/common/context.py
  11. 9
      magnum/common/docker_utils.py
  12. 31
      magnum/common/exception.py
  13. 22
      magnum/common/keystone.py
  14. 6
      magnum/common/policy.py
  15. 4
      magnum/common/rpc_service.py
  16. 30
      magnum/conductor/api.py
  17. 268
      magnum/conductor/handlers/cluster_conductor.py
  18. 35
      magnum/conductor/handlers/common/trust_manager.py
  19. 14
      magnum/conductor/k8s_api.py
  20. 6
      magnum/conductor/k8s_monitor.py
  21. 6
      magnum/conductor/mesos_monitor.py
  22. 22
      magnum/conductor/monitors.py
  23. 16
      magnum/conductor/scale_manager.py
  24. 8
      magnum/conductor/swarm_monitor.py
  25. 40
      magnum/conductor/utils.py
  26. 59
      magnum/db/api.py
  27. 35
      magnum/db/sqlalchemy/alembic/versions/720f640f43d1_rename_bay_table_to_cluster.py
  28. 84
      magnum/db/sqlalchemy/api.py
  29. 10
      magnum/db/sqlalchemy/models.py
  30. 26
      magnum/drivers/common/k8s_template_def.py
  31. 127
      magnum/drivers/common/template_def.py
  32. 2
      magnum/drivers/common/templates/fragments/configure-docker-storage.sh
  33. 4
      magnum/drivers/k8s_coreos_v1/template_def.py
  34. 4
      magnum/drivers/k8s_coreos_v1/templates/fragments/make-cert-client.yaml
  35. 6
      magnum/drivers/k8s_coreos_v1/templates/fragments/make-cert.yaml
  36. 2
      magnum/drivers/k8s_coreos_v1/templates/fragments/write-heat-params-master.yaml
  37. 2
      magnum/drivers/k8s_coreos_v1/templates/fragments/write-heat-params.yaml
  38. 10
      magnum/drivers/k8s_coreos_v1/templates/kubecluster.yaml
  39. 8
      magnum/drivers/k8s_coreos_v1/templates/kubemaster.yaml
  40. 6
      magnum/drivers/k8s_coreos_v1/templates/kubeminion.yaml
  41. 20
      magnum/drivers/k8s_fedora_atomic_v1/template_def.py
  42. 6
      magnum/drivers/k8s_fedora_atomic_v1/templates/fragments/make-cert-client.sh
  43. 6
      magnum/drivers/k8s_fedora_atomic_v1/templates/fragments/make-cert.sh
  44. 2
      magnum/drivers/k8s_fedora_atomic_v1/templates/fragments/write-heat-params-master.yaml
  45. 2
      magnum/drivers/k8s_fedora_atomic_v1/templates/fragments/write-heat-params.yaml
  46. 10
      magnum/drivers/k8s_fedora_atomic_v1/templates/kubecluster-fedora-ironic.yaml
  47. 12
      magnum/drivers/k8s_fedora_atomic_v1/templates/kubecluster.yaml
  48. 8
      magnum/drivers/k8s_fedora_atomic_v1/templates/kubemaster-fedora-ironic.yaml
  49. 8
      magnum/drivers/k8s_fedora_atomic_v1/templates/kubemaster.yaml
  50. 6
      magnum/drivers/k8s_fedora_atomic_v1/templates/kubeminion-fedora-ironic.yaml
  51. 6
      magnum/drivers/k8s_fedora_atomic_v1/templates/kubeminion.yaml
  52. 18
      magnum/drivers/mesos_ubuntu_v1/template_def.py
  53. 2
      magnum/drivers/mesos_ubuntu_v1/templates/mesoscluster.yaml
  54. 6
      magnum/drivers/swarm_fedora_atomic_v1/image/openvswitch/README.rst
  55. 32
      magnum/drivers/swarm_fedora_atomic_v1/template_def.py
  56. 10
      magnum/drivers/swarm_fedora_atomic_v1/templates/cluster.yaml
  57. 8
      magnum/drivers/swarm_fedora_atomic_v1/templates/fragments/make-cert.py
  58. 0
      magnum/drivers/swarm_fedora_atomic_v1/templates/fragments/write-cluster-failure-service.yaml
  59. 2
      magnum/drivers/swarm_fedora_atomic_v1/templates/fragments/write-heat-params-master.yaml
  60. 2
      magnum/drivers/swarm_fedora_atomic_v1/templates/fragments/write-heat-params-node.yaml
  61. 10
      magnum/drivers/swarm_fedora_atomic_v1/templates/swarmmaster.yaml
  62. 8
      magnum/drivers/swarm_fedora_atomic_v1/templates/swarmnode.yaml
  63. 6
      magnum/objects/__init__.py
  64. 142
      magnum/objects/cluster.py
  65. 5
      magnum/objects/cluster_template.py
  66. 16
      magnum/objects/fields.py
  67. 4
      magnum/opts.py
  68. 183
      magnum/service/periodic.py
  69. 2
      magnum/tests/contrib/copy_instance_logs.sh
  70. 2
      magnum/tests/contrib/post_test_hook.sh
  71. 6
      magnum/tests/unit/api/controllers/test_root.py
  72. 144
      magnum/tests/unit/api/controllers/v1/test_bay.py
  73. 12
      magnum/tests/unit/api/controllers/v1/test_baymodel.py
  74. 80
      magnum/tests/unit/api/controllers/v1/test_cluster.py
  75. 16
      magnum/tests/unit/api/controllers/v1/test_cluster_template.py
  76. 30
      magnum/tests/unit/api/controllers/v1/test_utils.py
  77. 182
      magnum/tests/unit/api/test_validation.py
  78. 11
      magnum/tests/unit/api/utils.py
  79. 12
      magnum/tests/unit/common/test_keystone.py
  80. 54
      magnum/tests/unit/conductor/handlers/common/test_trust_manager.py
  81. 466
      magnum/tests/unit/conductor/handlers/test_cluster_conductor.py
  82. 110
      magnum/tests/unit/conductor/handlers/test_k8s_cluster_conductor.py
  83. 66
      magnum/tests/unit/conductor/handlers/test_mesos_cluster_conductor.py
  84. 76
      magnum/tests/unit/conductor/handlers/test_swarm_cluster_conductor.py
  85. 51
      magnum/tests/unit/conductor/test_monitors.py
  86. 32
      magnum/tests/unit/conductor/test_rpcapi.py
  87. 18
      magnum/tests/unit/conductor/test_scale_manager.py
  88. 75
      magnum/tests/unit/conductor/test_utils.py
  89. 30
      magnum/tests/unit/db/sqlalchemy/test_types.py
  90. 214
      magnum/tests/unit/db/test_bay.py
  91. 214
      magnum/tests/unit/db/test_cluster.py
  92. 6
      magnum/tests/unit/db/test_cluster_template.py
  93. 28
      magnum/tests/unit/db/utils.py
  94. 265
      magnum/tests/unit/drivers/test_template_definition.py
  95. 192
      magnum/tests/unit/objects/test_bay.py
  96. 195
      magnum/tests/unit/objects/test_cluster.py
  97. 12
      magnum/tests/unit/objects/test_fields.py
  98. 4
      magnum/tests/unit/objects/test_objects.py
  99. 48
      magnum/tests/unit/objects/utils.py
  100. 226
      magnum/tests/unit/service/test_periodic.py

4
magnum/api/controllers/base.py

@ -143,12 +143,12 @@ class Controller(rest.RestController):
Example:
@base.Controller.api_version("1.1", "1.2")
@expose.expose(Cluster, types.uuid_or_name)
def get_one(self, bay_ident):
def get_one(self, cluster_ident):
{...code for versions 1.1 to 1.2...}
@base.Controller.api_version("1.3")
@expose.expose(Cluster, types.uuid_or_name)
def get_one(self, bay_ident):
def get_one(self, cluster_ident):
{...code for versions 1.3 to latest}
@min_ver: string representing minimum version

99
magnum/api/controllers/v1/bay.py

@ -28,7 +28,7 @@ from magnum.api.controllers.v1 import collection
from magnum.api.controllers.v1 import types
from magnum.api import expose
from magnum.api import utils as api_utils
from magnum.api.validation import validate_bay_properties
from magnum.api.validation import validate_cluster_properties
from magnum.common import clients
from magnum.common import exception
from magnum.common import name_generator
@ -66,7 +66,7 @@ class Bay(base.APIBase):
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 Bay
# response for a POST request to create a Cluster
e.code = 400 # BadRequest
raise
elif value == wtypes.Unset:
@ -99,7 +99,7 @@ class Bay(base.APIBase):
stack_id = wsme.wsattr(wtypes.text, readonly=True)
"""Stack id of the heat stack"""
status = wtypes.Enum(str, *fields.BayStatus.ALL)
status = wtypes.Enum(str, *fields.ClusterStatus.ALL)
"""Status of the bay from the heat stack"""
status_reason = wtypes.text
@ -131,13 +131,43 @@ class Bay(base.APIBase):
super(Bay, self).__init__()
self.fields = []
for field in objects.Bay.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:
@ -167,7 +197,7 @@ class Bay(base.APIBase):
master_count=1,
bay_create_timeout=15,
stack_id='49dc23f5-ffc9-40c3-9d34-7be7f9e34d63',
status=fields.BayStatus.CREATE_COMPLETE,
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'],
@ -177,6 +207,24 @@ class Bay(base.APIBase):
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 BayPatchType(types.JsonPatchType):
_api_base = Bay
@ -239,12 +287,12 @@ class BaysController(base.Controller):
marker_obj = None
if marker:
marker_obj = objects.Bay.get_by_uuid(pecan.request.context,
marker)
marker_obj = objects.Cluster.get_by_uuid(pecan.request.context,
marker)
bays = objects.Bay.list(pecan.request.context, limit,
marker_obj, sort_key=sort_key,
sort_dir=sort_dir)
bays = objects.Cluster.list(pecan.request.context, limit,
marker_obj, sort_key=sort_key,
sort_dir=sort_dir)
return BayCollection.convert_with_links(bays, limit,
url=resource_url,
@ -323,13 +371,13 @@ class BaysController(base.Controller):
:param bay_ident: UUID of a bay or logical name of the bay.
"""
context = pecan.request.context
bay = api_utils.get_resource('Bay', bay_ident)
bay = api_utils.get_resource('Cluster', bay_ident)
policy.enforce(context, 'bay:get', bay,
action='bay:get')
bay = Bay.convert_with_links(bay)
if bay.status in fields.BayStatus.STATUS_FAILED:
if bay.status in fields.ClusterStatus.STATUS_FAILED:
bay.bay_faults = self._collect_fault_info(context, bay)
return bay
@ -342,8 +390,8 @@ class BaysController(base.Controller):
:param bay: a bay within the request body.
"""
new_bay = self._post(bay)
res_bay = pecan.request.rpcapi.bay_create(new_bay,
bay.bay_create_timeout)
res_bay = pecan.request.rpcapi.cluster_create(new_bay,
bay.bay_create_timeout)
# Set the HTTP Location Header
pecan.response.location = link.build_url('bays', res_bay.uuid)
@ -357,7 +405,8 @@ class BaysController(base.Controller):
:param bay: a bay within the request body.
"""
new_bay = self._post(bay)
pecan.request.rpcapi.bay_create_async(new_bay, bay.bay_create_timeout)
pecan.request.rpcapi.cluster_create_async(new_bay,
bay.bay_create_timeout)
return BayID(new_bay.uuid)
def _post(self, bay):
@ -378,7 +427,7 @@ class BaysController(base.Controller):
bay_dict['coe_version'] = None
bay_dict['container_version'] = None
new_bay = objects.Bay(context, **bay_dict)
new_bay = objects.Cluster(context, **bay_dict)
new_bay.uuid = uuid.uuid4()
return new_bay
@ -392,7 +441,7 @@ class BaysController(base.Controller):
:param patch: a json PATCH document to apply to this bay.
"""
bay = self._patch(bay_ident, patch)
res_bay = pecan.request.rpcapi.bay_update(bay)
res_bay = pecan.request.rpcapi.cluster_update(bay)
return Bay.convert_with_links(res_bay)
@base.Controller.api_version("1.2", "1.2") # noqa
@ -406,7 +455,7 @@ class BaysController(base.Controller):
:param patch: a json PATCH document to apply to this bay.
"""
bay = self._patch(bay_ident, patch)
pecan.request.rpcapi.bay_update_async(bay)
pecan.request.rpcapi.cluster_update_async(bay)
return BayID(bay.uuid)
@base.Controller.api_version("1.3") # noqa
@ -421,12 +470,12 @@ class BaysController(base.Controller):
:param patch: a json PATCH document to apply to this bay.
"""
bay = self._patch(bay_ident, patch)
pecan.request.rpcapi.bay_update_async(bay, rollback=rollback)
pecan.request.rpcapi.cluster_update_async(bay, rollback=rollback)
return BayID(bay.uuid)
def _patch(self, bay_ident, patch):
context = pecan.request.context
bay = api_utils.get_resource('Bay', bay_ident)
bay = api_utils.get_resource('Cluster', bay_ident)
policy.enforce(context, 'bay:update', bay,
action='bay:update')
try:
@ -436,7 +485,7 @@ class BaysController(base.Controller):
raise exception.PatchError(patch=patch, reason=e)
# Update only the fields that have changed
for field in objects.Bay.fields:
for field in objects.Cluster.fields:
try:
patch_val = getattr(new_bay, field)
except AttributeError:
@ -449,7 +498,7 @@ class BaysController(base.Controller):
delta = bay.obj_what_changed()
validate_bay_properties(delta)
validate_cluster_properties(delta)
return bay
@base.Controller.api_version("1.1", "1.1")
@ -461,7 +510,7 @@ class BaysController(base.Controller):
"""
bay = self._delete(bay_ident)
pecan.request.rpcapi.bay_delete(bay.uuid)
pecan.request.rpcapi.cluster_delete(bay.uuid)
@base.Controller.api_version("1.2") # noqa
@expose.expose(None, types.uuid_or_name, status_code=204)
@ -472,11 +521,11 @@ class BaysController(base.Controller):
"""
bay = self._delete(bay_ident)
pecan.request.rpcapi.bay_delete_async(bay.uuid)
pecan.request.rpcapi.cluster_delete_async(bay.uuid)
def _delete(self, bay_ident):
context = pecan.request.context
bay = api_utils.get_resource('Bay', bay_ident)
bay = api_utils.get_resource('Cluster', bay_ident)
policy.enforce(context, 'bay:delete', bay,
action='bay:delete')
return bay

4
magnum/api/controllers/v1/baymodel.py

@ -46,7 +46,7 @@ class BayModel(base.APIBase):
name = wtypes.StringType(min_length=1, max_length=255)
"""The name of the Baymodel"""
coe = wtypes.Enum(str, *fields.BayType.ALL, mandatory=True)
coe = wtypes.Enum(str, *fields.ClusterType.ALL, mandatory=True)
"""The Container Orchestration Engine for this bay model"""
image_id = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255),
@ -181,7 +181,7 @@ class BayModel(base.APIBase):
docker_volume_size=25,
docker_storage_driver='devicemapper',
cluster_distro='fedora-atomic',
coe=fields.BayType.KUBERNETES,
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',

9
magnum/api/controllers/v1/certificate.py

@ -46,11 +46,11 @@ class Certificate(base.APIBase):
def _set_cluster_uuid(self, value):
if value and self._cluster_uuid != value:
try:
self._cluster = api_utils.get_resource('Bay', value)
self._cluster = api_utils.get_resource('Cluster', value)
self._cluster_uuid = self._cluster.uuid
except exception.ClusterNotFound as e:
# 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
raise
elif value == wtypes.Unset:
@ -90,7 +90,8 @@ class Certificate(base.APIBase):
def get_cluster(self):
if not self._cluster:
self._cluster = api_utils.get_resource('Bay', self.cluster_uuid)
self._cluster = api_utils.get_resource('Cluster',
self.cluster_uuid)
return self._cluster
@staticmethod
@ -141,7 +142,7 @@ class CertificateController(base.Controller):
logical name of the cluster.
"""
context = pecan.request.context
cluster = api_utils.get_resource('Bay', cluster_ident)
cluster = api_utils.get_resource('Cluster', cluster_ident)
policy.enforce(context, 'certificate:get', cluster,
action='certificate:get')
certificate = pecan.request.rpcapi.get_ca_certificate(cluster)

89
magnum/api/controllers/v1/cluster.py

@ -28,7 +28,7 @@ from magnum.api.controllers.v1 import collection
from magnum.api.controllers.v1 import types
from magnum.api import expose
from magnum.api import utils as api_utils
from magnum.api.validation import validate_bay_properties
from magnum.api.validation import validate_cluster_properties
from magnum.common import clients
from magnum.common import exception
from magnum.common import name_generator
@ -110,7 +110,7 @@ class Cluster(base.APIBase):
stack_id = wsme.wsattr(wtypes.text, readonly=True)
"""Stack id of the heat stack"""
status = wtypes.Enum(str, *fields.BayStatus.ALL)
status = wtypes.Enum(str, *fields.ClusterStatus.ALL)
"""Status of the cluster from the heat stack"""
status_reason = wtypes.text
@ -141,36 +141,13 @@ class Cluster(base.APIBase):
def __init__(self, **kwargs):
super(Cluster, self).__init__()
self.fields = []
for field in objects.Bay.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 clusters
self.fields.append('cluster_template_id')
if 'cluster_template_id' in kwargs.keys():
setattr(self, 'cluster_template_id',
kwargs.get('cluster_template_id', wtypes.Unset))
else:
setattr(self, 'cluster_template_id', kwargs.get('baymodel_id',
wtypes.Unset))
self.fields.append('create_timeout')
if 'create_timeout' in kwargs.keys():
setattr(self, 'create_timeout', kwargs.get('create_timeout',
wtypes.Unset))
else:
setattr(self, 'create_timeout', kwargs.get('bay_create_timeout',
wtypes.Unset))
self.fields.append('faults')
if 'faults' in kwargs.keys():
setattr(self, 'faults', kwargs.get('faults', wtypes.Unset))
else:
setattr(self, 'faults', kwargs.get('bay_faults', wtypes.Unset))
@staticmethod
def _convert_with_links(cluster, url, expand=True):
if not expand:
@ -180,9 +157,9 @@ class Cluster(base.APIBase):
'stack_id'])
cluster.links = [link.Link.make_link('self', url,
'bays', cluster.uuid),
'clusters', cluster.uuid),
link.Link.make_link('bookmark', url,
'bays', cluster.uuid,
'clusters', cluster.uuid,
bookmark=True)]
return cluster
@ -201,7 +178,7 @@ class Cluster(base.APIBase):
master_count=1,
create_timeout=15,
stack_id='49dc23f5-ffc9-40c3-9d34-7be7f9e34d63',
status=fields.BayStatus.CREATE_COMPLETE,
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'],
@ -211,26 +188,6 @@ class Cluster(base.APIBase):
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 updated cluster values
d = super(Cluster, self).as_dict()
if 'cluster_template_id' in d.keys():
d['baymodel_id'] = d['cluster_template_id']
del d['cluster_template_id']
if 'create_timeout' in d.keys():
d['bay_create_timeout'] = d['create_timeout']
del d['create_timeout']
if 'faults' in d.keys():
d['bay_faults'] = d['faults']
del d['faults']
return d
class ClusterPatchType(types.JsonPatchType):
_api_base = Cluster
@ -295,12 +252,12 @@ class ClustersController(base.Controller):
marker_obj = None
if marker:
marker_obj = objects.Bay.get_by_uuid(pecan.request.context,
marker)
marker_obj = objects.Cluster.get_by_uuid(pecan.request.context,
marker)
clusters = objects.Bay.list(pecan.request.context, limit,
marker_obj, sort_key=sort_key,
sort_dir=sort_dir)
clusters = objects.Cluster.list(pecan.request.context, limit,
marker_obj, sort_key=sort_key,
sort_dir=sort_dir)
return ClusterCollection.convert_with_links(clusters, limit,
url=resource_url,
@ -380,13 +337,13 @@ class ClustersController(base.Controller):
:param cluster_ident: UUID or logical name of the Cluster.
"""
context = pecan.request.context
cluster = api_utils.get_resource('Bay', cluster_ident)
cluster = api_utils.get_resource('Cluster', cluster_ident)
policy.enforce(context, 'cluster:get', cluster,
action='cluster:get')
cluster = Cluster.convert_with_links(cluster)
if cluster.status in fields.BayStatus.STATUS_FAILED:
if cluster.status in fields.ClusterStatus.STATUS_FAILED:
cluster.faults = self._collect_fault_info(context, cluster)
return cluster
@ -420,10 +377,10 @@ class ClustersController(base.Controller):
cluster_dict['coe_version'] = None
cluster_dict['container_version'] = None
new_cluster = objects.Bay(context, **cluster_dict)
new_cluster = objects.Cluster(context, **cluster_dict)
new_cluster.uuid = uuid.uuid4()
pecan.request.rpcapi.bay_create_async(new_cluster,
cluster.create_timeout)
pecan.request.rpcapi.cluster_create_async(new_cluster,
cluster.create_timeout)
return ClusterID(new_cluster.uuid)
@ -438,7 +395,7 @@ class ClustersController(base.Controller):
:param patch: a json PATCH document to apply to this cluster.
"""
cluster = self._patch(cluster_ident, patch)
pecan.request.rpcapi.bay_update_async(cluster)
pecan.request.rpcapi.cluster_update_async(cluster)
return ClusterID(cluster.uuid)
@base.Controller.api_version("1.3") # noqa
@ -453,12 +410,12 @@ class ClustersController(base.Controller):
: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)
pecan.request.rpcapi.cluster_update_async(cluster, rollback)
return ClusterID(cluster.uuid)
def _patch(self, cluster_ident, patch):
context = pecan.request.context
cluster = api_utils.get_resource('Bay', cluster_ident)
cluster = api_utils.get_resource('Cluster', cluster_ident)
policy.enforce(context, 'cluster:update', cluster,
action='cluster:update')
try:
@ -469,7 +426,7 @@ class ClustersController(base.Controller):
raise exception.PatchError(patch=patch, reason=e)
# Update only the fields that have changed
for field in objects.Bay.fields:
for field in objects.Cluster.fields:
try:
patch_val = getattr(new_cluster, field)
except AttributeError:
@ -482,7 +439,7 @@ class ClustersController(base.Controller):
delta = cluster.obj_what_changed()
validate_bay_properties(delta)
validate_cluster_properties(delta)
return cluster
@expose.expose(None, types.uuid_or_name, status_code=204)
@ -492,8 +449,8 @@ class ClustersController(base.Controller):
:param cluster_ident: UUID of cluster or logical name of the cluster.
"""
context = pecan.request.context
cluster = api_utils.get_resource('Bay', cluster_ident)
cluster = api_utils.get_resource('Cluster', cluster_ident)
policy.enforce(context, 'cluster:delete', cluster,
action='cluster:delete')
pecan.request.rpcapi.bay_delete_async(cluster.uuid)
pecan.request.rpcapi.cluster_delete_async(cluster.uuid)

4
magnum/api/controllers/v1/cluster_template.py

@ -47,7 +47,7 @@ class ClusterTemplate(base.APIBase):
name = wtypes.StringType(min_length=1, max_length=255)
"""The name of the ClusterTemplate"""
coe = wtypes.Enum(str, *fields.BayType.ALL, mandatory=True)
coe = wtypes.Enum(str, *fields.ClusterType.ALL, mandatory=True)
"""The Container Orchestration Engine for this clustertemplate"""
image_id = wsme.wsattr(wtypes.StringType(min_length=1, max_length=255),
@ -185,7 +185,7 @@ class ClusterTemplate(base.APIBase):
docker_volume_size=25,
docker_storage_driver='devicemapper',
cluster_distro='fedora-atomic',
coe=fields.BayType.KUBERNETES,
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',

39
magnum/api/validation.py

@ -65,32 +65,35 @@ cluster_template_opts = [
cfg.CONF.register_opts(cluster_template_opts, group='cluster_template')
bay_update_allowed_properties = set(['node_count'])
cluster_update_allowed_properties = set(['node_count'])
def enforce_bay_types(*bay_types):
"""Enforce that bay_type is in supported list."""
def enforce_cluster_types(*cluster_types):
"""Enforce that cluster_type is in supported list."""
@decorator.decorator
def wrapper(func, *args, **kwargs):
# Note(eliqiao): This decorator has some assumptions
# args[1] should be an APIBase instance or
# args[2] should be a bay_ident
# args[2] should be a cluster_ident
obj = args[1]
if hasattr(obj, 'bay_uuid'):
bay = objects.Bay.get_by_uuid(pecan.request.context, obj.bay_uuid)
if hasattr(obj, 'cluster_uuid'):
cluster = objects.Cluster.get_by_uuid(pecan.request.context,
obj.cluster_uuid)
else:
bay_ident = args[2]
if uuidutils.is_uuid_like(bay_ident):
bay = objects.Bay.get_by_uuid(pecan.request.context, bay_ident)
cluster_ident = args[2]
if uuidutils.is_uuid_like(cluster_ident):
cluster = objects.Cluster.get_by_uuid(pecan.request.context,
cluster_ident)
else:
bay = objects.Bay.get_by_name(pecan.request.context, bay_ident)
cluster = objects.Cluster.get_by_name(pecan.request.context,
cluster_ident)
if bay.cluster_template.coe not in bay_types:
if cluster.cluster_template.coe not in cluster_types:
raise exception.InvalidParameterValue(_(
'Cannot fulfill request with a %(bay_type)s bay, '
'expecting a %(supported_bay_types)s bay.') %
{'bay_type': bay.cluster_template.coe,
'supported_bay_types': '/'.join(bay_types)})
'Cannot fulfill request with a %(cluster_type)s cluster, '
'expecting a %(supported_cluster_types)s cluster.') %
{'cluster_type': cluster.cluster_template.coe,
'supported_cluster_types': '/'.join(cluster_types)})
return func(*args, **kwargs)
@ -192,11 +195,11 @@ def _enforce_volume_storage_size(cluster_template):
'driver.') % (volume_size, storage_driver)
def validate_bay_properties(delta):
def validate_cluster_properties(delta):
update_disallowed_properties = delta - bay_update_allowed_properties
update_disallowed_properties = delta - cluster_update_allowed_properties
if update_disallowed_properties:
err = (_("cannot change bay property(ies) %s.") %
err = (_("cannot change cluster property(ies) %s.") %
", ".join(update_disallowed_properties))
raise exception.InvalidParameterValue(err=err)

4
magnum/cmd/conductor.py

@ -25,8 +25,8 @@ from oslo_service import service
from magnum.common import rpc_service
from magnum.common import service as magnum_service
from magnum.common import short_id
from magnum.conductor.handlers import bay_conductor
from magnum.conductor.handlers import ca_conductor
from magnum.conductor.handlers import cluster_conductor
from magnum.conductor.handlers import conductor_listener
from magnum.conductor.handlers import indirection_api
from magnum.i18n import _LI
@ -49,7 +49,7 @@ def main():
conductor_id = short_id.generate_id()
endpoints = [
indirection_api.Handler(),
bay_conductor.Handler(),
cluster_conductor.Handler(),
conductor_listener.Handler(),
ca_conductor.Handler(),
]

6
magnum/cmd/template_manage.py

@ -50,7 +50,7 @@ class TemplateList(lister.Lister):
parser.add_argument('-d', '--details',
action='store_true',
dest='details',
help=('display the bay types provided by '
help=('display the cluster types provided by '
'each template'))
parser.add_argument('-p', '--paths',
action='store_true',
@ -77,10 +77,10 @@ class TemplateList(lister.Lister):
path=definition.template_path)
if parsed_args.details:
for bay_type in definition.provides:
for cluster_type in definition.provides:
row = dict()
row.update(template)
row.update(bay_type)
row.update(cluster_type)
rows.append(row)
else:
rows.append(template)

12
magnum/common/context.py

@ -105,15 +105,15 @@ def make_admin_context(show_deleted=False, all_tenants=False):
return context
def make_bay_context(bay, show_deleted=False):
"""Create a user context based on a bay's stored Keystone trust.
def make_cluster_context(cluster, show_deleted=False):
"""Create a user context based on a cluster's stored Keystone trust.
:param bay: the bay supplying the Keystone trust to use
:param cluster: the cluster supplying the Keystone trust to use
:param show_deleted: if True, will show deleted items when query db
"""
context = RequestContext(user_name=bay.trustee_username,
password=bay.trustee_password,
trust_id=bay.trust_id,
context = RequestContext(user_name=cluster.trustee_username,
password=cluster.trustee_password,
trust_id=cluster.trust_id,
show_deleted=show_deleted,
user_domain_id=CONF.trust.trustee_domain_id,
user_domain_name=CONF.trust.trustee_domain_name)

9
magnum/common/docker_utils.py

@ -75,20 +75,21 @@ def is_docker_api_version_atleast(docker, version):
@contextlib.contextmanager
def docker_for_bay(context, bay):
cluster_template = conductor_utils.retrieve_cluster_template(context, bay)
def docker_for_cluster(context, cluster):
cluster_template = conductor_utils.retrieve_cluster_template(
context, cluster)
ca_cert, magnum_key, magnum_cert = None, None, None
client_kwargs = dict()
if not cluster_template.tls_disabled:
(ca_cert, magnum_key,
magnum_cert) = cert_manager.create_client_files(bay)
magnum_cert) = cert_manager.create_client_files(cluster)
client_kwargs['ca_cert'] = ca_cert.name
client_kwargs['client_key'] = magnum_key.name
client_kwargs['client_cert'] = magnum_cert.name
yield DockerHTTPClient(
bay.api_address,
cluster.api_address,
CONF.docker.docker_remote_api_version,
CONF.docker.default_timeout,
**client_kwargs

31
magnum/common/exception.py

@ -154,7 +154,7 @@ class GetDiscoveryUrlFailed(MagnumException):
message = _("Failed to get discovery url from '%(discovery_endpoint)s'.")
class InvalidBayDiscoveryURL(Invalid):
class InvalidClusterDiscoveryURL(Invalid):
message = _("Invalid discovery URL '%(discovery_url)s'.")
@ -271,11 +271,11 @@ class PodAlreadyExists(Conflict):
class PodListNotFound(ResourceNotFound):
message = _("Pod list could not be found for Bay %(bay_uuid)s.")
message = _("Pod list could not be found for Cluster %(cluster_uuid)s.")
class PodCreationFailed(Invalid):
message = _("Pod creation failed in Bay %(bay_uuid)s.")
message = _("Pod creation failed in Cluster %(cluster_uuid)s.")
class ServiceNotFound(ResourceNotFound):
@ -287,11 +287,12 @@ class ServiceAlreadyExists(Conflict):
class ServiceListNotFound(ResourceNotFound):
message = _("Service list could not be found for Bay %(bay_uuid)s.")
message = _("Service list could not be found for Cluster "
"%(cluster_uuid)s.")
class ServiceCreationFailed(Invalid):
message = _("Service creation failed for Bay %(bay_uuid)s.")
message = _("Service creation failed for Cluster %(cluster_uuid)s.")
class ContainerException(Exception):
@ -303,13 +304,13 @@ class NotSupported(MagnumException):
code = 400
class BayTypeNotSupported(MagnumException):
message = _("Bay type (%(server_type)s, %(os)s, %(coe)s)"
class ClusterTypeNotSupported(MagnumException):
message = _("Cluster type (%(server_type)s, %(os)s, %(coe)s)"
" not supported.")
class BayTypeNotEnabled(MagnumException):
message = _("Bay type (%(server_type)s, %(os)s, %(coe)s)"
class ClusterTypeNotEnabled(MagnumException):
message = _("Cluster type (%(server_type)s, %(os)s, %(coe)s)"
" not enabled.")
@ -322,7 +323,8 @@ class Urllib2InvalidScheme(MagnumException):
class OperationInProgress(Invalid):
message = _("Bay %(bay_name)s already has an operation in progress.")
message = _("Cluster %(cluster_name)s already has an operation in "
"progress.")
class ImageNotFound(ResourceNotFound):
@ -383,11 +385,11 @@ class MagnumServiceAlreadyExists(Conflict):
class UnsupportedK8sQuantityFormat(MagnumException):
message = _("Unsupported quantity format for k8s bay.")
message = _("Unsupported quantity format for k8s cluster.")
class UnsupportedDockerQuantityFormat(MagnumException):
message = _("Unsupported quantity format for Swarm bay.")
message = _("Unsupported quantity format for Swarm cluster.")
class FlavorNotFound(ResourceNotFound):
@ -429,8 +431,9 @@ class RegionsListFailed(MagnumException):
message = _("Failed to list regions.")
class TrusteeOrTrustToBayFailed(MagnumException):
message = _("Failed to create trustee or trust for Bay: %(bay_uuid)s")
class TrusteeOrTrustToClusterFailed(MagnumException):
message = _("Failed to create trustee or trust for Cluster: "
"%(cluster_uuid)s")
class CertificatesToClusterFailed(MagnumException):

22
magnum/common/keystone.py

@ -32,9 +32,9 @@ LOG = logging.getLogger(__name__)
trust_opts = [
cfg.StrOpt('trustee_domain_id',
help=_('Id of the domain to create trustee for bays')),
help=_('Id of the domain to create trustee for clusters')),
cfg.StrOpt('trustee_domain_name',
help=_('Name of the domain to create trustee for bays')),
help=_('Name of the domain to create trustee for s')),
cfg.StrOpt('trustee_domain_admin_id',
help=_('Id of the admin with roles sufficient to manage users'
' in the trustee_domain')),
@ -256,21 +256,21 @@ class KeystoneClientV3(object):
trustee_user_id=trustee_user)
return trust
def delete_trust(self, context, bay):
if bay.trust_id is None:
def delete_trust(self, context, cluster):
if cluster.trust_id is None:
return
# Trust can only be deleted by the user who creates it. So when
# other users in the same project want to delete the bay, we need
# other users in the same project want to delete the cluster, we need
# use the trustee which can impersonate the trustor to delete the
# trust.
if context.user_id == bay.user_id:
if context.user_id == cluster.user_id:
client = self.client
else:
auth = ka_v3.Password(auth_url=self.auth_url,
user_id=bay.trustee_user_id,
password=bay.trustee_password,
trust_id=bay.trust_id)
user_id=cluster.trustee_user_id,
password=cluster.trustee_password,
trust_id=cluster.trust_id)
sess = ka_loading.session.Session().load_from_options(
auth=auth,
@ -280,12 +280,12 @@ class KeystoneClientV3(object):
cert=CONF[CFG_LEGACY_GROUP].certfile)
client = kc_v3.Client(session=sess)
try:
client.trusts.delete(bay.trust_id)
client.trusts.delete(cluster.trust_id)
except kc_exception.NotFound:
pass
except Exception:
LOG.exception(_LE('Failed to delete trust'))
raise exception.TrustDeleteFailed(trust_id=bay.trust_id)
raise exception.TrustDeleteFailed(trust_id=cluster.trust_id)
def create_trustee(self, username, password):
domain_id = self.trustee_domain_id

6
magnum/common/policy.py

@ -104,11 +104,11 @@ def enforce_wsgi(api_name, act=None):
example:
from magnum.common import policy
class BaysController(rest.RestController):
class ClustersController(rest.RestController):
....
@policy.enforce_wsgi("bay", "delete")
@policy.enforce_wsgi("cluster", "delete")
@wsme_pecan.wsexpose(None, types.uuid_or_name, status_code=204)
def delete(self, bay_ident):
def delete(self, cluster_ident):
...
"""
@decorator.decorator

4
magnum/common/rpc_service.py

@ -44,8 +44,8 @@ TRANSPORT_ALIASES = {
periodic_opts = [
cfg.BoolOpt('periodic_global_stack_list',
default=False,
help="List Heat stacks globally when syncing bays. "
"Default is to do retrieve each bay's stack "
help="List Heat stacks globally when syncing clusters. "
"Default is to do retrieve each cluster's stack "
"individually. Reduces number of requests against "
"Heat API if enabled but requires changes to Heat's "
"policy.json."),

30
magnum/conductor/api.py

@ -28,27 +28,27 @@ class API(rpc_service.API):
super(API, self).__init__(transport, context,
topic=cfg.CONF.conductor.topic)
# Bay Operations
# Cluster Operations
def bay_create(self, bay, bay_create_timeout):
return self._call('bay_create', bay=bay,
bay_create_timeout=bay_create_timeout)
def cluster_create(self, cluster, create_timeout):
return self._call('cluster_create', cluster=cluster,
create_timeout=create_timeout)
def bay_create_async(self, bay, bay_create_timeout):
self._cast('bay_create', bay=bay,
bay_create_timeout=bay_create_timeout)
def cluster_create_async(self, cluster, create_timeout):
self._cast('cluster_create', cluster=cluster,
create_timeout=create_timeout)
def bay_delete(self, uuid):
return self._call('bay_delete', uuid=uuid)
def cluster_delete(self, uuid):
return self._call('cluster_delete', uuid=uuid)
def bay_delete_async(self, uuid):
self._cast('bay_delete', uuid=uuid)
def cluster_delete_async(self, uuid):
self._cast('cluster_delete', uuid=uuid)
def bay_update(self, bay):
return self._call('bay_update', bay=bay)
def cluster_update(self, cluster):
return self._call('cluster_update', cluster=cluster)
def bay_update_async(self, bay, rollback=False):
self._cast('bay_update', bay=bay, rollback=rollback)
def cluster_update_async(self, cluster, rollback=False):
self._cast('cluster_update', cluster=cluster, rollback=rollback)
# CA operations

268
magnum/conductor/handlers/bay_conductor.py → magnum/conductor/handlers/cluster_conductor.py

@ -68,8 +68,9 @@ CONF.register_opts(cluster_heat_opts, group='cluster_heat')
LOG = logging.getLogger(__name__)
def _extract_template_definition(context, bay, scale_manager=None):
cluster_template = conductor_utils.retrieve_cluster_template(context, bay)
def _extract_template_definition(context, cluster, scale_manager=None):
cluster_template = conductor_utils.retrieve_cluster_template(context,
cluster)
cluster_distro = cluster_template.cluster_distro
cluster_coe = cluster_template.coe
cluster_server_type = cluster_template.server_type
@ -77,7 +78,7 @@ def _extract_template_definition(context, bay, scale_manager=None):
cluster_server_type,
cluster_distro,
cluster_coe)
return definition.extract_definition(context, cluster_template, bay,
return definition.extract_definition(context, cluster_template, cluster,
scale_manager=scale_manager)
@ -91,9 +92,9 @@ def _get_env_files(template_path, env_rel_paths):
return environment_files, env_map
def _create_stack(context, osc, bay, bay_create_timeout):
def _create_stack(context, osc, cluster, create_timeout):
template_path, heat_params, env_files = (
_extract_template_definition(context, bay))
_extract_template_definition(context, cluster))
tpl_files, template = template_utils.get_template_contents(template_path)
@ -101,11 +102,11 @@ def _create_stack(context, osc, bay, bay_create_timeout):
tpl_files.update(env_map)
# Make sure no duplicate stack name
stack_name = '%s-%s' % (bay.name, short_id.generate_id())
if bay_create_timeout:
heat_timeout = bay_create_timeout
stack_name = '%s-%s' % (cluster.name, short_id.generate_id())
if create_timeout:
heat_timeout = create_timeout
else:
# no bay_create_timeout value was passed in to the request
# no create_timeout value was passed in to the request
# so falling back on configuration file value
heat_timeout = cfg.CONF.cluster_heat.create_timeout
fields = {
@ -121,9 +122,9 @@ def _create_stack(context, osc, bay, bay_create_timeout):
return created_stack
def _update_stack(context, osc, bay, scale_manager=None, rollback=False):
def _update_stack(context, osc, cluster, scale_manager=None, rollback=False):
template_path, heat_params, env_files = _extract_template_definition(
context, bay, scale_manager=scale_manager)
context, cluster, scale_manager=scale_manager)
tpl_files, template = template_utils.get_template_contents(template_path)
environment_files, env_map = _get_env_files(template_path, env_files)
@ -137,7 +138,7 @@ def _update_stack(context, osc, bay, scale_manager=None, rollback=False):
'disable_rollback': not rollback
}
return osc.heat().stacks.update(bay.stack_id, **fields)
return osc.heat().stacks.update(cluster.stack_id, **fields)
class Handler(object):
@ -145,26 +146,28 @@ class Handler(object):
def __init__(self):
super(Handler, self).__init__()
# Bay Operations
# Cluster Operations
def bay_create(self, context, bay, bay_create_timeout):
LOG.debug('bay_heat bay_create')
def cluster_create(self, context, cluster, create_timeout):
LOG.debug('cluster_heat cluster_create')
osc = clients.OpenStackClients(context)
try:
# Create trustee/trust and set them to bay
trust_manager.create_trustee_and_trust(osc, bay)
# Generate certificate and set the cert reference to bay
cert_manager.generate_certificates_to_cluster(bay, context=context)
conductor_utils.notify_about_bay_operation(
# Create trustee/trust and set them to cluster
trust_manager.create_trustee_and_trust(osc, cluster)
# Generate certificate and set the cert reference to cluster
cert_manager.generate_certificates_to_cluster(cluster,
context=context)
conductor_utils.notify_about_cluster_operation(
context, taxonomy.ACTION_CREATE, taxonomy.OUTCOME_PENDING)
created_stack = _create_stack(context, osc, bay,
bay_create_timeout)
created_stack = _create_stack(context, osc, cluster,
create_timeout)
except Exception as e:
cert_manager.delete_certificates_from_cluster(bay, context=context)
trust_manager.delete_trustee_and_trust(osc, context, bay)
conductor_utils.notify_about_bay_operation(
cert_manager.delete_certificates_from_cluster(cluster,
context=context)
trust_manager.delete_trustee_and_trust(osc, context, cluster)
conductor_utils.notify_about_cluster_operation(
context, taxonomy.ACTION_CREATE, taxonomy.OUTCOME_FAILURE)
if isinstance(e, exc.HTTPBadRequest):
@ -173,111 +176,112 @@ class Handler(object):
raise e
raise
bay.stack_id = created_stack['stack']['id']
bay.status = fields.BayStatus.CREATE_IN_PROGRESS
bay.create()
cluster.stack_id = created_stack['stack']['id']
cluster.status = fields.ClusterStatus.CREATE_IN_PROGRESS
cluster.create()
self._poll_and_check(osc, bay)
self._poll_and_check(osc, cluster)
return bay
return cluster
def bay_update(self, context, bay, rollback=False):
LOG.debug('bay_heat bay_update')
def cluster_update(self, context, cluster, rollback=False):
LOG.debug('cluster_heat cluster_update')
osc = clients.OpenStackClients(context)
stack = osc.heat().stacks.get(bay.stack_id)
stack = osc.heat().stacks.get(cluster.stack_id)
allow_update_status = (
fields.BayStatus.CREATE_COMPLETE,
fields.BayStatus.UPDATE_COMPLETE,
fields.BayStatus.RESUME_COMPLETE,
fields.BayStatus.RESTORE_COMPLETE,
fields.BayStatus.ROLLBACK_COMPLETE,
fields.BayStatus.SNAPSHOT_COMPLETE,
fields.BayStatus.CHECK_COMPLETE,
fields.BayStatus.ADOPT_COMPLETE
fields.ClusterStatus.CREATE_COMPLETE,
fields.ClusterStatus.UPDATE_COMPLETE,
fields.ClusterStatus.RESUME_COMPLETE,
fields.ClusterStatus.RESTORE_COMPLETE,
fields.ClusterStatus.ROLLBACK_COMPLETE,
fields.ClusterStatus.SNAPSHOT_COMPLETE,
fields.ClusterStatus.CHECK_COMPLETE,
fields.ClusterStatus.ADOPT_COMPLETE
)
if stack.stack_status not in allow_update_status:
conductor_utils.notify_about_bay_operation(
conductor_utils.notify_about_cluster_operation(
context, taxonomy.ACTION_UPDATE, taxonomy.OUTCOME_FAILURE)
operation = _('Updating a bay when stack status is '
operation = _('Updating a cluster when stack status is '
'"%s"') % stack.stack_status
raise exception.NotSupported(operation=operation)
delta = bay.obj_what_changed()
delta = cluster.obj_what_changed()
if not delta:
return bay
return cluster
manager = scale_manager.ScaleManager(context, osc, bay)
manager = scale_manager.ScaleManager(context, osc, cluster)
conductor_utils.notify_about_bay_operation(
conductor_utils.notify_about_cluster_operation(
context, taxonomy.ACTION_UPDATE, taxonomy.OUTCOME_PENDING)
_update_stack(context, osc, bay, manager, rollback)
self._poll_and_check(osc, bay)
_update_stack(context, osc, cluster, manager, rollback)
self._poll_and_check(osc, cluster)
return bay
return cluster
def bay_delete(self, context, uuid):
LOG.debug('bay_heat bay_delete')
def cluster_delete(self, context, uuid):
LOG.debug('cluster_heat cluster_delete')
osc = clients.OpenStackClients(context)
bay = objects.Bay.get_by_uuid(context, uuid)
cluster = objects.Cluster.get_by_uuid(context, uuid)
stack_id = bay.stack_id
stack_id = cluster.stack_id
# NOTE(sdake): This will execute a stack_delete operation. This will
# Ignore HTTPNotFound exceptions (stack wasn't present). In the case
# that Heat couldn't find the stack representing the bay, likely a user
# has deleted the stack outside the context of Magnum. Therefore the
# contents of the bay are forever lost.
# that Heat couldn't find the stack representing the cluster, likely a
# user has deleted the stack outside the context of Magnum. Therefore
# the contents of the cluster are forever lost.
#
# If the exception is unhandled, the original exception will be raised.
try:
conductor_utils.notify_about_bay_operation(
conductor_utils.notify_about_cluster_operation(
context, taxonomy.ACTION_DELETE, taxonomy.OUTCOME_PENDING)
osc.heat().stacks.delete(stack_id)
except exc.HTTPNotFound:
LOG.info(_LI('The stack %s was not found during bay'
LOG.info(_LI('The stack %s was not found during cluster'
' deletion.'), stack_id)
try:
trust_manager.delete_trustee_and_trust(osc, context, bay)
cert_manager.delete_certificates_from_cluster(bay,
trust_manager.delete_trustee_and_trust(osc, context, cluster)
cert_manager.delete_certificates_from_cluster(cluster,
context=context)
bay.destroy()
cluster.destroy()
except exception.ClusterNotFound:
LOG.info(_LI('The bay %s has been deleted by others.'), uuid)
conductor_utils.notify_about_bay_operation(
LOG.info(_LI('The cluster %s has been deleted by others.'),
uuid)
conductor_utils.notify_about_cluster_operation(
context, taxonomy.ACTION_DELETE, taxonomy.OUTCOME_SUCCESS)
return None
except exc.HTTPConflict:
conductor_utils.notify_about_bay_operation(
conductor_utils.notify_about_cluster_operation(
context, taxonomy.ACTION_DELETE, taxonomy.OUTCOME_FAILURE)
raise exception.OperationInProgress(bay_name=bay.name)
raise exception.OperationInProgress(cluster_name=cluster.name)
except Exception:
conductor_utils.notify_about_bay_operation(
conductor_utils.notify_about_cluster_operation(
context, taxonomy.ACTION_DELETE, taxonomy.OUTCOME_FAILURE)
raise
bay.status = fields.BayStatus.DELETE_IN_PROGRESS
bay.save()
cluster.status = fields.ClusterStatus.DELETE_IN_PROGRESS
cluster.save()
self._poll_and_check(osc, bay)
self._poll_and_check(osc, cluster)
return None
def _poll_and_check(self, osc, bay):
poller = HeatPoller(osc, bay)
def _poll_and_check(self, osc, cluster):
poller = HeatPoller(osc, cluster)
lc = loopingcall.FixedIntervalLoopingCall(f=poller.poll_and_check)
lc.start(cfg.CONF.cluster_heat.wait_interval, True)
class HeatPoller(object):
def __init__(self, openstack_client, bay):
def __init__(self, openstack_client, cluster):
self.openstack_client = openstack_client
self.context = self.openstack_client.context
self.bay = bay
self.cluster = cluster
self.attempts = 0
self.cluster_template = conductor_utils.retrieve_cluster_template(
self.context, bay)
self.context, cluster)
self.template_def = \
template_def.TemplateDefinition.get_template_definition(
self.cluster_template.server_type,
@ -286,97 +290,97 @@ class HeatPoller(object):
def poll_and_check(self):
# TODO(yuanying): temporary implementation to update api_address,
# node_addresses and bay status
stack = self.openstack_client.heat().stacks.get(self.bay.stack_id)
# node_addresses and cluster status
stack = self.openstack_client.heat().stacks.get(self.cluster.stack_id)
self.attempts += 1
status_to_event = {
fields.BayStatus.DELETE_COMPLETE: taxonomy.ACTION_DELETE,
fields.BayStatus.CREATE_COMPLETE: taxonomy.ACTION_CREATE,
fields.BayStatus.UPDATE_COMPLETE: taxonomy.ACTION_UPDATE,
fields.BayStatus.ROLLBACK_COMPLETE: taxonomy.ACTION_UPDATE,
fields.BayStatus.CREATE_FAILED: taxonomy.ACTION_CREATE,
fields.BayStatus.DELETE_FAILED: taxonomy.ACTION_DELETE,
fields.BayStatus.UPDATE_FAILED: taxonomy.ACTION_UPDATE,
fields.BayStatus.ROLLBACK_FAILED: taxonomy.ACTION_UPDATE
fields.ClusterStatus.DELETE_COMPLETE: taxonomy.ACTION_DELETE,
fields.ClusterStatus.CREATE_COMPLETE: taxonomy.ACTION_CREATE,
fields.ClusterStatus.UPDATE_COMPLETE: taxonomy.ACTION_UPDATE,
fields.ClusterStatus.ROLLBACK_COMPLETE: taxonomy.ACTION_UPDATE,
fields.ClusterStatus.CREATE_FAILED: taxonomy.ACTION_CREATE,
fields.ClusterStatus.DELETE_FAILED: taxonomy.ACTION_DELETE,
fields.ClusterStatus.UPDATE_FAILED: taxonomy.ACTION_UPDATE,
fields.ClusterStatus.ROLLBACK_FAILED: taxonomy.ACTION_UPDATE
}
# poll_and_check is detached and polling long time to check status,
# so another user/client can call delete bay/stack.
if stack.stack_status == fields.BayStatus.DELETE_COMPLETE:
# so another user/client can call delete cluster/stack.
if stack.stack_status == fields.ClusterStatus.DELETE_COMPLETE:
self._delete_complete()
conductor_utils.notify_about_bay_operation(