Rename BayModel DB, Object, and internal usage to ClusterTemplate

This patch is the first of 3 patches to change the internal
usage of the terms Bay and BayModel. This patch updates
BayModel to ClusterTemplate. No functionality should be
changed by this patch, just naming and db updates.

Change-Id: I0803e81be6482962be2878a8ea2c7480f89111ac
Implements: blueprint rename-bay-to-cluster
changes/70/359470/9
Jaycen Grant 2016-08-23 15:37:33 -07:00
parent 42abb07835
commit 0b7c6401dd
38 changed files with 1065 additions and 932 deletions

View File

@ -62,7 +62,7 @@ class Bay(base.APIBase):
def _set_baymodel_id(self, value):
if value and self._baymodel_id != value:
try:
baymodel = api_utils.get_resource('BayModel', value)
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
@ -364,7 +364,8 @@ class BaysController(base.Controller):
context = pecan.request.context
policy.enforce(context, 'bay:create',
action='bay:create')
baymodel = objects.BayModel.get_by_uuid(context, bay.baymodel_id)
baymodel = objects.ClusterTemplate.get_by_uuid(context,
bay.baymodel_id)
attr_validator.validate_os_resources(context, baymodel.as_dict())
attr_validator.validate_master_count(bay.as_dict(), baymodel.as_dict())
bay_dict = bay.as_dict()

View File

@ -141,7 +141,7 @@ class BayModel(base.APIBase):
def __init__(self, **kwargs):
self.fields = []
for field in objects.BayModel.fields:
for field in objects.ClusterTemplate.fields:
# Skip fields we do not expose.
if not hasattr(self, field):
continue
@ -251,12 +251,12 @@ class BayModelsController(base.Controller):
marker_obj = None
if marker:
marker_obj = objects.BayModel.get_by_uuid(pecan.request.context,
marker)
marker_obj = objects.ClusterTemplate.get_by_uuid(
pecan.request.context, marker)
baymodels = objects.BayModel.list(pecan.request.context, limit,
marker_obj, sort_key=sort_key,
sort_dir=sort_dir)
baymodels = objects.ClusterTemplate.list(pecan.request.context, limit,
marker_obj, sort_key=sort_key,
sort_dir=sort_dir)
return BayModelCollection.convert_with_links(baymodels, limit,
url=resource_url,
@ -311,7 +311,7 @@ class BayModelsController(base.Controller):
:param baymodel_ident: UUID or logical name of a baymodel.
"""
context = pecan.request.context
baymodel = api_utils.get_resource('BayModel', baymodel_ident)
baymodel = api_utils.get_resource('ClusterTemplate', baymodel_ident)
if not baymodel.public:
policy.enforce(context, 'baymodel:get', baymodel,
action='baymodel:get')
@ -350,7 +350,7 @@ class BayModelsController(base.Controller):
name = arg_name or self._generate_name_for_baymodel(context)
baymodel_dict['name'] = name
new_baymodel = objects.BayModel(context, **baymodel_dict)
new_baymodel = objects.ClusterTemplate(context, **baymodel_dict)
new_baymodel.create()
# Set the HTTP Location Header
pecan.response.location = link.build_url('baymodels',
@ -368,7 +368,7 @@ class BayModelsController(base.Controller):
:param patch: a json PATCH document to apply to this baymodel.
"""
context = pecan.request.context
baymodel = api_utils.get_resource('BayModel', baymodel_ident)
baymodel = api_utils.get_resource('ClusterTemplate', baymodel_ident)
policy.enforce(context, 'baymodel:update', baymodel,
action='baymodel:update')
try:
@ -388,7 +388,7 @@ class BayModelsController(base.Controller):
raise exception.ClusterTemplatePublishDenied()
# Update only the fields that have changed
for field in objects.BayModel.fields:
for field in objects.ClusterTemplate.fields:
try:
patch_val = getattr(new_baymodel, field)
except AttributeError:
@ -409,7 +409,7 @@ class BayModelsController(base.Controller):
:param baymodel_ident: UUID or logical name of a baymodel.
"""
context = pecan.request.context
baymodel = api_utils.get_resource('BayModel', baymodel_ident)
baymodel = api_utils.get_resource('ClusterTemplate', baymodel_ident)
policy.enforce(context, 'baymodel:delete', baymodel,
action='baymodel:delete')
baymodel.destroy()

View File

@ -70,7 +70,8 @@ class Cluster(base.APIBase):
def _set_cluster_template_id(self, value):
if value and self._cluster_template_id != value:
try:
cluster_template = api_utils.get_resource('BayModel', value)
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
@ -400,7 +401,8 @@ class ClustersController(base.Controller):
policy.enforce(context, 'cluster:create',
action='cluster:create')
temp_id = cluster.cluster_template_id
cluster_template = objects.BayModel.get_by_uuid(context, temp_id)
cluster_template = objects.ClusterTemplate.get_by_uuid(context,
temp_id)
cluster_dict = cluster.as_dict()
attr_validator.validate_os_resources(context,

View File

@ -142,7 +142,7 @@ class ClusterTemplate(base.APIBase):
def __init__(self, **kwargs):
self.fields = []
for field in objects.BayModel.fields:
for field in objects.ClusterTemplate.fields:
# Skip fields we do not expose.
if not hasattr(self, field):
continue
@ -255,13 +255,12 @@ class ClusterTemplatesController(base.Controller):
marker_obj = None
if marker:
marker_obj = objects.BayModel.get_by_uuid(pecan.request.context,
marker)
marker_obj = objects.ClusterTemplate.get_by_uuid(
pecan.request.context, marker)
cluster_templates = objects.BayModel.list(pecan.request.context, limit,
marker_obj,
sort_key=sort_key,
sort_dir=sort_dir)
cluster_templates = objects.ClusterTemplate.list(
pecan.request.context, limit, marker_obj, sort_key=sort_key,
sort_dir=sort_dir)
return ClusterTemplateCollection.convert_with_links(cluster_templates,
limit,
@ -319,7 +318,7 @@ class ClusterTemplatesController(base.Controller):
ClusterTemplate.
"""
context = pecan.request.context
cluster_template = api_utils.get_resource('BayModel',
cluster_template = api_utils.get_resource('ClusterTemplate',
cluster_template_ident)
if not cluster_template.public:
policy.enforce(context, 'clustertemplate:get', cluster_template,
@ -360,8 +359,8 @@ class ClusterTemplatesController(base.Controller):
name = arg_name or self._generate_name_for_cluster_template(context)
cluster_template_dict['name'] = name
new_cluster_template = objects.BayModel(context,
**cluster_template_dict)
new_cluster_template = objects.ClusterTemplate(context,
**cluster_template_dict)
new_cluster_template.create()
# Set the HTTP Location Header
pecan.response.location = link.build_url('clustertemplates',
@ -382,7 +381,7 @@ class ClusterTemplatesController(base.Controller):
ClusterTemplate.
"""
context = pecan.request.context
cluster_template = api_utils.get_resource('BayModel',
cluster_template = api_utils.get_resource('ClusterTemplate',
cluster_template_ident)
policy.enforce(context, 'clustertemplate:update', cluster_template,
action='clustertemplate:update')
@ -404,7 +403,7 @@ class ClusterTemplatesController(base.Controller):
raise exception.ClusterTemplatePublishDenied()
# Update only the fields that have changed
for field in objects.BayModel.fields:
for field in objects.ClusterTemplate.fields:
try:
patch_val = getattr(new_cluster_template, field)
except AttributeError:
@ -426,7 +425,7 @@ class ClusterTemplatesController(base.Controller):
ClusterTemplate.
"""
context = pecan.request.context
cluster_template = api_utils.get_resource('BayModel',
cluster_template = api_utils.get_resource('ClusterTemplate',
cluster_template_ident)
policy.enforce(context, 'clustertemplate:delete', cluster_template,
action='clustertemplate:delete')

View File

@ -85,11 +85,11 @@ def enforce_bay_types(*bay_types):
else:
bay = objects.Bay.get_by_name(pecan.request.context, bay_ident)
if bay.baymodel.coe not in bay_types:
if bay.cluster_template.coe not in bay_types:
raise exception.InvalidParameterValue(_(
'Cannot fulfill request with a %(bay_type)s bay, '
'expecting a %(supported_bay_types)s bay.') %
{'bay_type': bay.baymodel.coe,
{'bay_type': bay.cluster_template.coe,
'supported_bay_types': '/'.join(bay_types)})
return func(*args, **kwargs)
@ -100,8 +100,8 @@ def enforce_bay_types(*bay_types):
def enforce_network_driver_types_create():
@decorator.decorator
def wrapper(func, *args, **kwargs):
baymodel = args[1]
_enforce_network_driver_types(baymodel)
cluster_template = args[1]
_enforce_network_driver_types(cluster_template)
return func(*args, **kwargs)
return wrapper
@ -110,33 +110,35 @@ def enforce_network_driver_types_create():
def enforce_network_driver_types_update():
@decorator.decorator
def wrapper(func, *args, **kwargs):
baymodel_ident = args[1]
cluster_template_ident = args[1]
patch = args[2]
baymodel = api_utils.get_resource('BayModel', baymodel_ident)
cluster_template = api_utils.get_resource('ClusterTemplate',
cluster_template_ident)
try:
baymodel_dict = api_utils.apply_jsonpatch(baymodel.as_dict(),
patch)
cluster_template_dict = api_utils.apply_jsonpatch(
cluster_template.as_dict(), patch)
except api_utils.JSONPATCH_EXCEPTIONS as e:
raise exception.PatchError(patch=patch, reason=e)
baymodel = objects.BayModel(pecan.request.context, **baymodel_dict)
_enforce_network_driver_types(baymodel)
cluster_template = objects.ClusterTemplate(pecan.request.context,
**cluster_template_dict)
_enforce_network_driver_types(cluster_template)
return func(*args, **kwargs)
return wrapper
def _enforce_network_driver_types(baymodel):
validator = Validator.get_coe_validator(baymodel.coe)
if not baymodel.network_driver:
baymodel.network_driver = validator.default_network_driver
validator.validate_network_driver(baymodel.network_driver)
def _enforce_network_driver_types(cluster_template):
validator = Validator.get_coe_validator(cluster_template.coe)
if not cluster_template.network_driver:
cluster_template.network_driver = validator.default_network_driver
validator.validate_network_driver(cluster_template.network_driver)
def enforce_volume_driver_types_create():
@decorator.decorator
def wrapper(func, *args, **kwargs):
baymodel = args[1]
_enforce_volume_driver_types(baymodel.as_dict())
cluster_template = args[1]
_enforce_volume_driver_types(cluster_template.as_dict())
return func(*args, **kwargs)
return wrapper
@ -145,8 +147,8 @@ def enforce_volume_driver_types_create():
def enforce_volume_storage_size_create():
@decorator.decorator
def wrapper(func, *args, **kwargs):
baymodel = args[1]
_enforce_volume_storage_size(baymodel.as_dict())
cluster_template = args[1]
_enforce_volume_storage_size(cluster_template.as_dict())
return func(*args, **kwargs)
return wrapper
@ -155,32 +157,33 @@ def enforce_volume_storage_size_create():
def enforce_volume_driver_types_update():
@decorator.decorator
def wrapper(func, *args, **kwargs):
baymodel_ident = args[1]
cluster_template_ident = args[1]
patch = args[2]
baymodel = api_utils.get_resource('BayModel', baymodel_ident)
cluster_template = api_utils.get_resource('ClusterTemplate',
cluster_template_ident)
try:
baymodel_dict = api_utils.apply_jsonpatch(baymodel.as_dict(),
patch)
cluster_template_dict = api_utils.apply_jsonpatch(
cluster_template.as_dict(), patch)
except api_utils.JSONPATCH_EXCEPTIONS as e:
raise exception.PatchError(patch=patch, reason=e)
_enforce_volume_driver_types(baymodel_dict)
_enforce_volume_driver_types(cluster_template_dict)
return func(*args, **kwargs)
return wrapper
def _enforce_volume_driver_types(baymodel):
validator = Validator.get_coe_validator(baymodel['coe'])
if not baymodel.get('volume_driver'):
def _enforce_volume_driver_types(cluster_template):
validator = Validator.get_coe_validator(cluster_template['coe'])
if not cluster_template.get('volume_driver'):
return
validator.validate_volume_driver(baymodel['volume_driver'])
validator.validate_volume_driver(cluster_template['volume_driver'])
def _enforce_volume_storage_size(baymodel):
if not baymodel.get('docker_volume_size'):
def _enforce_volume_storage_size(cluster_template):
if not cluster_template.get('docker_volume_size'):
return
volume_size = baymodel.get('docker_volume_size')
storage_driver = baymodel.get('docker_storage_driver')
volume_size = cluster_template.get('docker_volume_size')
storage_driver = cluster_template.get('docker_storage_driver')
if storage_driver == 'devicemapper':
if volume_size < 3:
raise exception.InvalidParameterValue(

View File

@ -76,11 +76,11 @@ def is_docker_api_version_atleast(docker, version):
@contextlib.contextmanager
def docker_for_bay(context, bay):
baymodel = conductor_utils.retrieve_baymodel(context, bay)
cluster_template = conductor_utils.retrieve_cluster_template(context, bay)
ca_cert, magnum_key, magnum_cert = None, None, None
client_kwargs = dict()
if not baymodel.tls_disabled:
if not cluster_template.tls_disabled:
(ca_cert, magnum_key,
magnum_cert) = cert_manager.create_client_files(bay)
client_kwargs['ca_cert'] = ca_cert.name

View File

@ -69,14 +69,14 @@ LOG = logging.getLogger(__name__)
def _extract_template_definition(context, bay, scale_manager=None):
baymodel = conductor_utils.retrieve_baymodel(context, bay)
cluster_distro = baymodel.cluster_distro
cluster_coe = baymodel.coe
cluster_server_type = baymodel.server_type
cluster_template = conductor_utils.retrieve_cluster_template(context, bay)
cluster_distro = cluster_template.cluster_distro
cluster_coe = cluster_template.coe
cluster_server_type = cluster_template.server_type
definition = TDef.get_template_definition(cluster_server_type,
cluster_distro,
cluster_coe)
return definition.extract_definition(context, baymodel, bay,
return definition.extract_definition(context, cluster_template, bay,
scale_manager=scale_manager)
@ -275,10 +275,11 @@ class HeatPoller(object):
self.context = self.openstack_client.context
self.bay = bay
self.attempts = 0
self.baymodel = conductor_utils.retrieve_baymodel(self.context, bay)
self.cluster_template = conductor_utils.retrieve_cluster_template(
self.context, bay)
self.template_def = TDef.get_template_definition(
self.baymodel.server_type,
self.baymodel.cluster_distro, self.baymodel.coe)
self.cluster_template.server_type,
self.cluster_template.cluster_distro, self.cluster_template.coe)
def poll_and_check(self):
# TODO(yuanying): temporary implementation to update api_address,
@ -374,9 +375,9 @@ class HeatPoller(object):
if stack_param:
self.bay.coe_version = stack.parameters[stack_param]
tdef = TDef.get_template_definition(self.baymodel.server_type,
self.baymodel.cluster_distro,
self.baymodel.coe)
tdef = TDef.get_template_definition(
self.cluster_template.server_type,
self.cluster_template.cluster_distro, self.cluster_template.coe)
version_module_path = tdef.driver_module_path+'.version'
try:
@ -387,7 +388,8 @@ class HeatPoller(object):
self.bay.container_version = container_version
def _sync_bay_and_template_status(self, stack):
self.template_def.update_outputs(stack, self.baymodel, self.bay)
self.template_def.update_outputs(stack, self.cluster_template,
self.bay)
self.get_version_info(stack)
self._sync_bay_status(stack)

View File

@ -68,9 +68,11 @@ class MonitorBase(object):
def create_monitor(context, bay):
if bay.baymodel.coe in COE_CLASS_PATH:
coe_cls = importutils.import_class(COE_CLASS_PATH[bay.baymodel.coe])
if bay.cluster_template.coe in COE_CLASS_PATH:
coe_cls = importutils.import_class(
COE_CLASS_PATH[bay.cluster_template.coe])
return coe_cls(context, bay)
LOG.debug("Cannot create monitor with bay type '%s'", bay.baymodel.coe)
LOG.debug("Cannot create monitor with bay type '%s'",
bay.cluster_template.coe)
return None

View File

@ -21,7 +21,7 @@ from pycadf import resource
from magnum.common import clients
from magnum.common import rpc
from magnum.objects import bay
from magnum.objects import baymodel
from magnum.objects import cluster_template
def retrieve_bay(context, bay_ident):
@ -31,8 +31,9 @@ def retrieve_bay(context, bay_ident):
return bay.Bay.get_by_uuid(context, bay_ident)
def retrieve_baymodel(context, bay):
return baymodel.BayModel.get_by_uuid(context, bay.baymodel_id)
def retrieve_cluster_template(context, bay):
return cluster_template.ClusterTemplate.get_by_uuid(context,
bay.baymodel_id)
def retrieve_bay_uuid(context, bay_ident):

View File

@ -122,18 +122,18 @@ class Connection(object):
"""
@abc.abstractmethod
def get_baymodel_list(self, context, filters=None,
limit=None, marker=None, sort_key=None,
sort_dir=None):
"""Get matching baymodels.
def get_cluster_template_list(self, context, filters=None,
limit=None, marker=None, sort_key=None,
sort_dir=None):
"""Get matching ClusterTemplates.
Return a list of the specified columns for all baymodels that match the
specified filters.
Return a list of the specified columns for all ClusterTemplates that
match the specified filters.
:param context: The security context
:param filters: Filters to apply. Defaults to None.
:param limit: Maximum number of baymodels to return.
:param limit: Maximum number of ClusterTemplates to return.
:param marker: the last item of the previous page; we return the next
result set.
:param sort_key: Attribute by which results should be sorted.
@ -143,12 +143,13 @@ class Connection(object):
"""
@abc.abstractmethod
def create_baymodel(self, values):
"""Create a new baymodel.
def create_cluster_template(self, values):
"""Create a new ClusterTemplate.
:param values: A dict containing several items used to identify
and track the baymodel, and several dicts which are
passed into the Drivers when managing this baymodel.
and track the ClusterTemplate, and several dicts which
are passed into the Drivers when managing this
ClusterTemplate.
For example:
::
@ -158,49 +159,49 @@ class Connection(object):
'name': 'example',
'type': 'virt'
}
:returns: A baymodel.
:returns: A ClusterTemplate.
"""
@abc.abstractmethod
def get_baymodel_by_id(self, context, baymodel_id):
"""Return a baymodel.
def get_cluster_template_by_id(self, context, cluster_template_id):
"""Return a ClusterTemplate.
:param context: The security context
:param baymodel_id: The id of a baymodel.
:returns: A baymodel.
:param cluster_template_id: The id of a ClusterTemplate.
:returns: A ClusterTemplate.
"""
@abc.abstractmethod
def get_baymodel_by_uuid(self, context, baymodel_uuid):
"""Return a baymodel.
def get_cluster_template_by_uuid(self, context, cluster_template_uuid):
"""Return a ClusterTemplate.
:param context: The security context
:param baymodel_uuid: The uuid of a baymodel.
:returns: A baymodel.
:param cluster_template_uuid: The uuid of a ClusterTemplate.
:returns: A ClusterTemplate.
"""
@abc.abstractmethod
def get_baymodel_by_name(self, context, baymodel_name):
"""Return a baymodel.
def get_cluster_template_by_name(self, context, cluster_template_name):
"""Return a ClusterTemplate.
:param context: The security context
:param baymodel_name: The name of a baymodel.
:returns: A baymodel.
:param cluster_template_name: The name of a ClusterTemplate.
:returns: A ClusterTemplate.
"""
@abc.abstractmethod
def destroy_baymodel(self, baymodel_id):
"""Destroy a baymodel and all associated interfaces.
def destroy_cluster_template(self, cluster_template_id):
"""Destroy a ClusterTemplate and all associated interfaces.
:param baymodel_id: The id or uuid of a baymodel.
:param cluster_template_id: The id or uuid of a ClusterTemplate.
"""
@abc.abstractmethod
def update_baymodel(self, baymodel_id, values):
"""Update properties of a baymodel.
def update_cluster_template(self, cluster_template_id, values):
"""Update properties of a ClusterTemplate.
:param baymodel_id: The id or uuid of a baymodel.
:returns: A baymodel.
:param cluster_template_id: The id or uuid of a ClusterTemplate.
:returns: A ClusterTemplate.
:raises: ClusterTemplateNotFound
"""

View File

@ -0,0 +1,28 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""rename_baymodel_to_clustertemplate
Revision ID: fb03fdef8919
Revises: fcb4efee8f8b
Create Date: 2016-08-31 12:40:31.165817
"""
# revision identifiers, used by Alembic.
revision = 'fb03fdef8919'
down_revision = 'fcb4efee8f8b'
from alembic import op
def upgrade():
op.rename_table('baymodel', 'cluster_template')

View File

@ -227,7 +227,7 @@ class Connection(api.Connection):
ref.update(values)
return ref
def _add_baymodels_filters(self, query, filters):
def _add_cluster_template_filters(self, query, filters):
if filters is None:
filters = {}
@ -242,124 +242,127 @@ class Connection(api.Connection):
return query.filter_by(**filter_dict)
def get_baymodel_list(self, context, filters=None, limit=None, marker=None,
sort_key=None, sort_dir=None):
query = model_query(models.BayModel)
def get_cluster_template_list(self, context, filters=None, limit=None,
marker=None, sort_key=None, sort_dir=None):
query = model_query(models.ClusterTemplate)
query = self._add_tenant_filters(context, query)
query = self._add_baymodels_filters(query, filters)
# include public baymodels
public_q = model_query(models.BayModel).filter_by(public=True)
query = self._add_cluster_template_filters(query, filters)
# include public ClusterTemplates
public_q = model_query(models.ClusterTemplate).filter_by(public=True)
query = query.union(public_q)
return _paginate_query(models.BayModel, limit, marker,
return _paginate_query(models.ClusterTemplate, limit, marker,
sort_key, sort_dir, query)
def create_baymodel(self, values):
# ensure defaults are present for new baymodels
def create_cluster_template(self, values):
# ensure defaults are present for new ClusterTemplates
if not values.get('uuid'):
values['uuid'] = uuidutils.generate_uuid()
baymodel = models.BayModel()
baymodel.update(values)
cluster_template = models.ClusterTemplate()
cluster_template.update(values)
try:
baymodel.save()
cluster_template.save()
except db_exc.DBDuplicateEntry:
raise exception.ClusterTemplateAlreadyExists(uuid=values['uuid'])
return baymodel
return cluster_template
def get_baymodel_by_id(self, context, baymodel_id):
query = model_query(models.BayModel)
def get_cluster_template_by_id(self, context, cluster_template_id):
query = model_query(models.ClusterTemplate)
query = self._add_tenant_filters(context, query)
public_q = model_query(models.BayModel).filter_by(public=True)
public_q = model_query(models.ClusterTemplate).filter_by(public=True)
query = query.union(public_q)
query = query.filter_by(id=baymodel_id)
query = query.filter_by(id=cluster_template_id)
try:
return query.one()
except NoResultFound:
raise exception.ClusterTemplateNotFound(
clustertemplate=baymodel_id)
clustertemplate=cluster_template_id)
def get_baymodel_by_uuid(self, context, baymodel_uuid):
query = model_query(models.BayModel)
def get_cluster_template_by_uuid(self, context, cluster_template_uuid):
query = model_query(models.ClusterTemplate)
query = self._add_tenant_filters(context, query)
public_q = model_query(models.BayModel).filter_by(public=True)
public_q = model_query(models.ClusterTemplate).filter_by(public=True)
query = query.union(public_q)
query = query.filter_by(uuid=baymodel_uuid)
query = query.filter_by(uuid=cluster_template_uuid)
try:
return query.one()
except NoResultFound:
raise exception.ClusterTemplateNotFound(
clustertemplate=baymodel_uuid)
clustertemplate=cluster_template_uuid)
def get_baymodel_by_name(self, context, baymodel_name):
query = model_query(models.BayModel)
def get_cluster_template_by_name(self, context, cluster_template_name):
query = model_query(models.ClusterTemplate)
query = self._add_tenant_filters(context, query)
public_q = model_query(models.BayModel).filter_by(public=True)
public_q = model_query(models.ClusterTemplate).filter_by(public=True)
query = query.union(public_q)
query = query.filter_by(name=baymodel_name)
query = query.filter_by(name=cluster_template_name)
try:
return query.one()
except MultipleResultsFound:
raise exception.Conflict('Multiple baymodels exist with same name.'
' Please use the baymodel uuid instead.')
raise exception.Conflict('Multiple ClusterTemplates exist with'
' same name. Please use the '
'ClusterTemplate uuid instead.')
except NoResultFound:
raise exception.ClusterTemplateNotFound(
clustertemplate=baymodel_name)
clustertemplate=cluster_template_name)
def _is_baymodel_referenced(self, session, baymodel_uuid):
"""Checks whether the baymodel is referenced by bay(s)."""
def _is_cluster_template_referenced(self, session, cluster_template_uuid):
"""Checks whether the ClusterTemplate is referenced by cluster(s)."""
query = model_query(models.Bay, session=session)
query = self._add_bays_filters(query, {'baymodel_id': baymodel_uuid})
query = self._add_bays_filters(query, {'baymodel_id':
cluster_template_uuid})
return query.count() != 0
def _is_publishing_baymodel(self, values):
def _is_publishing_cluster_template(self, values):
if (len(values) == 1 and
'public' in values and values['public'] is True):
return True
return False
def destroy_baymodel(self, baymodel_id):
def destroy_cluster_template(self, cluster_template_id):
session = get_session()
with session.begin():
query = model_query(models.BayModel, session=session)
query = add_identity_filter(query, baymodel_id)
query = model_query(models.ClusterTemplate, session=session)
query = add_identity_filter(query, cluster_template_id)
try:
baymodel_ref = query.one()
cluster_template_ref = query.one()
except NoResultFound:
raise exception.ClusterTemplateNotFound(
clustertemplate=baymodel_id)
clustertemplate=cluster_template_id)
if self._is_baymodel_referenced(session, baymodel_ref['uuid']):
if self._is_cluster_template_referenced(
session, cluster_template_ref['uuid']):
raise exception.ClusterTemplateReferenced(
clustertemplate=baymodel_id)
clustertemplate=cluster_template_id)
query.delete()
def update_baymodel(self, baymodel_id, values):
def update_cluster_template(self, cluster_template_id, values):
# NOTE(dtantsur): this can lead to very strange errors
if 'uuid' in values:
msg = _("Cannot overwrite UUID for an existing BayModel.")
msg = _("Cannot overwrite UUID for an existing ClusterTemplate.")
raise exception.InvalidParameterValue(err=msg)
return self._do_update_baymodel(baymodel_id, values)
return self._do_update_cluster_template(cluster_template_id, values)
def _do_update_baymodel(self, baymodel_id, values):
def _do_update_cluster_template(self, cluster_template_id, values):
session = get_session()
with session.begin():
query = model_query(models.BayModel, session=session)
query = add_identity_filter(query, baymodel_id)
query = model_query(models.ClusterTemplate, session=session)
query = add_identity_filter(query, cluster_template_id)
try:
ref = query.with_lockmode('update').one()
except NoResultFound:
raise exception.ClusterTemplateNotFound(
clustertemplate=baymodel_id)
clustertemplate=cluster_template_id)
if self._is_baymodel_referenced(session, ref['uuid']):
# we only allow to update baymodel to be public
if not self._is_publishing_baymodel(values):
if self._is_cluster_template_referenced(session, ref['uuid']):
# we only allow to update ClusterTemplate to be public
if not self._is_publishing_cluster_template(values):
raise exception.ClusterTemplateReferenced(
clustertemplate=baymodel_id)
clustertemplate=cluster_template_id)
ref.update(values)
return ref

View File

@ -141,10 +141,10 @@ class Bay(Base):
magnum_cert_ref = Column(String(512))
class BayModel(Base):
"""Represents a bay model."""
class ClusterTemplate(Base):
"""Represents a ClusterTemplate."""
__tablename__ = 'baymodel'
__tablename__ = 'cluster_template'
__table_args__ = (
schema.UniqueConstraint('uuid', name='uniq_baymodel0uuid'),
table_args()

View File

@ -13,19 +13,19 @@
# under the License.
from magnum.objects import bay
from magnum.objects import baymodel
from magnum.objects import certificate
from magnum.objects import cluster_template
from magnum.objects import magnum_service
from magnum.objects import x509keypair
Bay = bay.Bay
BayModel = baymodel.BayModel
ClusterTemplate = cluster_template.ClusterTemplate
MagnumService = magnum_service.MagnumService
X509KeyPair = x509keypair.X509KeyPair
Certificate = certificate.Certificate
__all__ = (Bay,
BayModel,
ClusterTemplate,
MagnumService,
X509KeyPair,
Certificate)

View File

@ -20,7 +20,7 @@ from oslo_versionedobjects import fields
from magnum.common import exception
from magnum.db import api as dbapi
from magnum.objects import base
from magnum.objects import baymodel
from magnum.objects import cluster_template
from magnum.objects import fields as m_fields
@ -32,12 +32,14 @@ class Bay(base.MagnumPersistentObject, base.MagnumObject,
# Version 1.2: Add 'registry_trust_id' field
# Version 1.3: Added 'baymodel' field
# Version 1.4: Added more types of status to bay's status field
# Version 1.5: Reanme 'registry_trust_id' to 'trust_id'
# Version 1.5: Rename 'registry_trust_id' to 'trust_id'
# Add 'trustee_user_name', 'trustee_password',
# 'trustee_user_id' field
# Version 1.6: Add rollback support for Bay
# Version 1.7: Added 'coe_version' and 'container_version' fields
VERSION = '1.7'
# Version 1.8: Rename 'baymodel' to 'cluster_template'
VERSION = '1.8'
dbapi = dbapi.get_instance()
@ -60,7 +62,7 @@ class Bay(base.MagnumPersistentObject, base.MagnumObject,
'master_addresses': fields.ListOfStringsField(nullable=True),
'ca_cert_ref': fields.StringField(nullable=True),
'magnum_cert_ref': fields.StringField(nullable=True),
'baymodel': fields.ObjectField('BayModel'),
'cluster_template': fields.ObjectField('ClusterTemplate'),
'trust_id': fields.StringField(nullable=True),
'trustee_username': fields.StringField(nullable=True),
'trustee_password': fields.StringField(nullable=True),
@ -73,15 +75,15 @@ class Bay(base.MagnumPersistentObject, base.MagnumObject,
def _from_db_object(bay, db_bay):
"""Converts a database entity to a formal object."""
for field in bay.fields:
if field != 'baymodel':
if field != 'cluster_template':
bay[field] = db_bay[field]
# Note(eliqiao): The following line needs to be placed outside the
# loop because there is a dependency from baymodel to baymodel_id.
# The baymodel_id must be populated first in the loop before it can be
# used to find the baymodel.
bay['baymodel'] = baymodel.BayModel.get_by_uuid(bay._context,
bay.baymodel_id)
# loop because there is a dependency from cluster_template to
# baymodel_id. The baymodel_id must be populated first in the loop
# before it can be used to find the cluster_template.
bay['cluster_template'] = cluster_template.ClusterTemplate.get_by_uuid(
bay._context, bay.baymodel_id)
bay.obj_reset_changes()
return bay

View File

@ -21,8 +21,8 @@ from magnum.objects import fields as m_fields
@base.MagnumObjectRegistry.register
class BayModel(base.MagnumPersistentObject, base.MagnumObject,
base.MagnumObjectDictCompat):
class ClusterTemplate(base.MagnumPersistentObject, base.MagnumObject,
base.MagnumObjectDictCompat):
# Version 1.0: Initial version
# Version 1.1: Add 'registry_enabled' field
# Version 1.2: Added 'network_driver' field
@ -39,7 +39,8 @@ class BayModel(base.MagnumPersistentObject, base.MagnumObject,
# Version 1.13: Added 'master_lb_enabled' field
# Version 1.14: Added 'fixed_subnet' field
# Version 1.15: Added 'floating_ip_enabled' field
VERSION = '1.15'
# Version 1.16: Renamed the class from "BayModel' to 'ClusterTemplate'
VERSION = '1.16'
dbapi = dbapi.get_instance()
@ -79,123 +80,129 @@ class BayModel(base.MagnumPersistentObject, base.MagnumObject,
}
@staticmethod
def _from_db_object(baymodel, db_baymodel):
def _from_db_object(cluster_template, db_cluster_template):
"""Converts a database entity to a formal object."""
for field in baymodel.fields:
baymodel[field] = db_baymodel[field]
for field in cluster_template.fields:
cluster_template[field] = db_cluster_template[field]
baymodel.obj_reset_changes()
return baymodel
cluster_template.obj_reset_changes()
return cluster_template
@staticmethod
def _from_db_object_list(db_objects, cls, context):
"""Converts a list of database entities to a list of formal objects."""
return [BayModel._from_db_object(cls(context), obj) for obj in
return [ClusterTemplate._from_db_object(cls(context), obj) for obj in
db_objects]
@base.remotable_classmethod
def get(cls, context, baymodel_id):
"""Find a baymodel based on its id or uuid and return a BayModel object.
def get(cls, context, cluster_template_id):
"""Find and return ClusterTemplate object based on its id or uuid.
:param baymodel_id: the id *or* uuid of a baymodel.
:param cluster_template_id: the id *or* uuid of a ClusterTemplate.
:param context: Security context
:returns: a :class:`BayModel` object.
:returns: a :class:`ClusterTemplate` object.
"""
if strutils.is_int_like(baymodel_id):
return cls.get_by_id(context, baymodel_id)
elif uuidutils.is_uuid_like(baymodel_id):
return cls.get_by_uuid(context, baymodel_id)
if strutils.is_int_like(cluster_template_id):
return cls.get_by_id(context, cluster_template_id)
elif uuidutils.is_uuid_like(cluster_template_id):
return cls.get_by_uuid(context, cluster_template_id)
else:
raise exception.InvalidIdentity(identity=baymodel_id)
raise exception.InvalidIdentity(identity=cluster_template_id)
@base.remotable_classmethod
def get_by_id(cls, context, baymodel_id):
"""Find a baymodel based on its integer id and return a BayModel object.
def get_by_id(cls, context, cluster_template_id):
"""Find and return ClusterTemplate object based on its integer id.
:param baymodel_id: the id of a baymodel.
:param cluster_template_id: the id of a ClusterTemplate.
:param context: Security context
:returns: a :class:`BayModel` object.
:returns: a :class:`ClusterTemplate` object.
"""
db_baymodel = cls.dbapi.get_baymodel_by_id(context, baymodel_id)
baymodel = BayModel._from_db_object(cls(context), db_baymodel)
return baymodel
db_cluster_template = cls.dbapi.get_cluster_template_by_id(
context, cluster_template_id)
cluster_template = ClusterTemplate._from_db_object(cls(context),
db_cluster_template)
return cluster_template
@base.remotable_classmethod
def get_by_uuid(cls, context, uuid):
"""Find a baymodel based on uuid and return a :class:`BayModel` object.
"""Find and return ClusterTemplate object based on uuid.
:param uuid: the uuid of a baymodel.
:param uuid: the uuid of a ClusterTemplate.
:param context: Security context
:returns: a :class:`BayModel` object.
:returns: a :class:`ClusterTemplate` object.
"""
db_baymodel = cls.dbapi.get_baymodel_by_uuid(context, uuid)
baymodel = BayModel._from_db_object(cls(context), db_baymodel)
return baymodel
db_cluster_template = cls.dbapi.get_cluster_template_by_uuid(
context, uuid)
cluster_template = ClusterTemplate._from_db_object(cls(context),
db_cluster_template)
return cluster_template
@base.remotable_classmethod
def get_by_name(cls, context, name):
"""Find a baymodel based on name and return a :class:`BayModel` object.
"""Find and return ClusterTemplate object based on name.
:param name: the name of a baymodel.
:param name: the name of a ClusterTemplate.
:param context: Security context
:returns: a :class:`BayModel` object.
:returns: a :class:`ClusterTemplate` object.
"""
db_baymodel = cls.dbapi.get_baymodel_by_name(context, name)
baymodel = BayModel._from_db_object(cls(context), db_baymodel)
return baymodel
db_cluster_template = cls.dbapi.get_cluster_template_by_name(context,
name)
cluster_template = ClusterTemplate._from_db_object(cls(context),
db_cluster_template)
return cluster_template
@base.remotable_classmethod
def list(cls, context, limit=None, marker=None,
sort_key=None, sort_dir=None):
"""Return a list of BayModel objects.
"""Return a list of ClusterTemplate objects.
:param context: Security context.
:param limit: maximum number of resources to return in a single result.
:param marker: pagination marker for large data sets.
:param sort_key: column to sort results by.
:param sort_dir: direction to sort. "asc" or "desc".
:returns: a list of :class:`BayModel` object.
:returns: a list of :class:`ClusterTemplate` object.
"""
db_baymodels = cls.dbapi.get_baymodel_list(context, limit=limit,
marker=marker,
sort_key=sort_key,
sort_dir=sort_dir)
return BayModel._from_db_object_list(db_baymodels, cls, context)
db_cluster_templates = cls.dbapi.get_cluster_template_list(
context, limit=limit, marker=marker, sort_key=sort_key,
sort_dir=sort_dir)
return ClusterTemplate._from_db_object_list(db_cluster_templates,
cls, context)
@base.remotable
def create(self, context=None):
"""Create a BayModel record in the DB.
"""Create a ClusterTemplate record in the DB.
:param context: Security context. NOTE: This should only
be used internally by the indirection_api.
Unfortunately, RPC requires context as the first
argument, even though we don't use it.
A context should be set when instantiating the
object, e.g.: BayModel(context)
object, e.g.: ClusterTemplate(context)
"""
values = self.obj_get_changes()
db_baymodel = self.dbapi.create_baymodel(values)
self._from_db_object(self, db_baymodel)
db_cluster_template = self.dbapi.create_cluster_template(values)
self._from_db_object(self, db_cluster_template)
@base.remotable
def destroy(self, context=None):
"""Delete the BayModel from the DB.
"""Delete the ClusterTemplate from the DB.
:param context: Security context. NOTE: This should only
be used internally by the indirection_api.
Unfortunately, RPC requires context as the first
argument, even though we don't use it.
A context should be set when instantiating the
object, e.g.: BayModel(context)
object, e.g.: ClusterTemplate(context)
"""
self.dbapi.destroy_baymodel(self.uuid)
self.dbapi.destroy_cluster_template(self.uuid)
self.obj_reset_changes()
@base.remotable
def save(self, context=None):
"""Save updates to this BayModel.
"""Save updates to this ClusterTemplate.
Updates will be made column by column based on the result
of self.what_changed().
@ -205,27 +212,27 @@ class BayModel(base.MagnumPersistentObject, base.MagnumObject,
Unfortunately, RPC requires context as the first
argument, even though we don't use it.
A context should be set when instantiating the
object, e.g.: BayModel(context)
object, e.g.: ClusterTemplate(context)
"""
updates = self.obj_get_changes()
self.dbapi.update_baymodel(self.uuid, updates)
self.dbapi.update_cluster_template(self.uuid, updates)
self.obj_reset_changes()
@base.remotable
def refresh(self, context=None):
"""Loads updates for this BayModel.
"""Loads updates for this ClusterTemplate.
Loads a baymodel with the same uuid from the database and
Loads a ClusterTemplate with the same uuid from the database and
checks for updated attributes. Updates are applied from
the loaded baymodel column by column, if there are any updates.
the loaded ClusterTemplate column by column, if there are any updates.
:param context: Security context. NOTE: This should only
be used internally by the indirection_api.
Unfortunately, RPC requires context as the first
argument, even though we don't use it.
A context should be set when instantiating the
object, e.g.: BayModel(context)
object, e.g.: ClusterTemplate(context)
"""
current = self.__class__.get_by_uuid(self._context, uuid=self.uuid)
for field in self.fields:

View File

@ -53,7 +53,7 @@ class TestListBay(api_base.FunctionalTest):
def setUp(self):
super(TestListBay, self).setUp()
obj_utils.create_test_baymodel(self.context)
obj_utils.create_test_cluster_template(self.context)
def test_empty(self):
response = self.get_json('/bays')
@ -207,7 +207,8 @@ class TestPatch(api_base.FunctionalTest):
def setUp(self):
super(TestPatch, self).setUp()
self.baymodel = obj_utils.create_test_baymodel(self.context)
self.cluster_template = obj_utils.create_test_cluster_template(
self.context)
self.bay = obj_utils.create_test_bay(self.context,
name='bay_example_A',
node_count=3)
@ -278,12 +279,12 @@ class TestPatch(api_base.FunctionalTest):
self.assertEqual(404, response.status_code)
def test_replace_baymodel_id_failed(self):
baymodel = obj_utils.create_test_baymodel(
cluster_template = obj_utils.create_test_cluster_template(
self.context,
uuid=uuidutils.generate_uuid())
response = self.patch_json('/bays/%s' % self.bay.uuid,
[{'path': '/baymodel_id',
'value': baymodel.uuid,
'value': cluster_template.uuid,
'op': 'replace'}],
expect_errors=True)
self.assertEqual('application/json', response.content_type)
@ -408,7 +409,8 @@ class TestPost(api_base.FunctionalTest):
def setUp(self):
super(TestPost, self).setUp()
self.baymodel = obj_utils.create_test_baymodel(self.context)
self.cluster_template = obj_utils.create_test_cluster_template(
self.context)
p = mock.patch.object(rpcapi.API, 'bay_create')
self.mock_bay_create = p.start()
self.mock_bay_create.side_effect = self._simulate_rpc_bay_create
@ -487,7 +489,7 @@ class TestPost(api_base.FunctionalTest):
self.assertTrue(response.json['errors'])
def test_create_bay_with_baymodel_name(self):
bdict = apiutils.bay_post_data(baymodel_id=self.baymodel.name)
bdict = apiutils.bay_post_data(baymodel_id=self.cluster_template.name)
response = self.post_json('/bays', bdict, expect_errors=True)
self.assertEqual('application/json', response.content_type)
self.assertEqual(201, response.status_int)
@ -733,18 +735,18 @@ class TestPost(api_base.FunctionalTest):
self.assertEqual(400, response.status_int)
def test_create_bay_with_no_lb_one_node(self):
baymodel = obj_utils.create_test_baymodel(
cluster_template = obj_utils.create_test_cluster_template(
self.context, name='foo', uuid='foo', master_lb_enabled=False)
bdict = apiutils.bay_post_data(baymodel_id=baymodel.name,
bdict = apiutils.bay_post_data(baymodel_id=cluster_template.name,
master_count=1)
response = self.post_json('/bays', bdict, expect_errors=True)
self.assertEqual('application/json', response.content_type)
self.assertEqual(201, response.status_int)
def test_create_bay_with_no_lb_multi_node(self):
baymodel = obj_utils.create_test_baymodel(
cluster_template = obj_utils.create_test_cluster_template(
self.context, name='foo', uuid='foo', master_lb_enabled=False)
bdict = apiutils.bay_post_data(baymodel_id=baymodel.name,
bdict = apiutils.bay_post_data(baymodel_id=cluster_template.name,
master_count=3)
response = self.post_json('/bays', bdict, expect_errors=True)
self.assertEqual('application/json', response.content_type)
@ -755,7 +757,8 @@ class TestDelete(api_base.FunctionalTest):
def setUp(self):
super(TestDelete, self).setUp()
self.baymodel = obj_utils.create_test_baymodel(self.context)
self.cluster_template = obj_utils.create_test_cluster_template(
self.context)
self.bay = obj_utils.create_test_bay(self.context)
p = mock.patch.object(rpcapi.API, 'bay_delete')
self.mock_bay_delete = p.start()
@ -807,7 +810,7 @@ class TestBayPolicyEnforcement(api_base.FunctionalTest):
def setUp(self):
super(TestBayPolicyEnforcement, self).setUp()
obj_utils.create_test_baymodel(self.context)
obj_utils.create_test_cluster_template(self.context)
def _common_policy_check(self, rule, func, *arg, **kwarg):
self.policy.set_rules({rule: "project:non_fake"})

View File

@ -56,20 +56,20 @@ class TestListBayModel(api_base.FunctionalTest):
self.assertEqual([], response['baymodels'])
def test_one(self):
baymodel = obj_utils.create_test_baymodel(self.context)
baymodel = obj_utils.create_test_cluster_template(self.context)
response = self.get_json('/baymodels')
self.assertEqual(baymodel.uuid, response['baymodels'][0]["uuid"])
self._verify_attrs(self._baymodel_attrs,
response['baymodels'][0])
def test_get_one(self):
baymodel = obj_utils.create_test_baymodel(self.context)
baymodel = obj_utils.create_test_cluster_template(self.context)
response = self.get_json('/baymodels/%s' % baymodel['uuid'])
self.assertEqual(baymodel.uuid, response['uuid'])
self._verify_attrs(self._baymodel_attrs, response)
def test_get_one_by_name(self):
baymodel = obj_utils.create_test_baymodel(self.context)
baymodel = obj_utils.create_test_cluster_template(self.context)
response = self.get_json('/baymodels/%s' % baymodel['name'])
self.assertEqual(baymodel.uuid, response['uuid'])
self._verify_attrs(self._baymodel_attrs, response)