Add coe attribute to BayModel

Add the Container Orchestration Engine (coe) attribute to the BayModel API,
model, and DB objects to be used by the Heat Conductor Handler when creating a
Bay.
1) Add coe attribute to BayModel models
2) Use coe attribute in heat handler's get_template_definition(...) calls

Partially implements: bp multiple-bay-templates

Change-Id: I15078c4327373df8fc6ebff8ad9a3d0cacdae572
This commit is contained in:
Janek Lehr 2015-04-21 13:48:23 -05:00
parent 5dfb30721c
commit 2ea49688c1
10 changed files with 119 additions and 34 deletions

2
.gitignore vendored
View File

@ -51,4 +51,4 @@ ChangeLog
# Editors
*~
.*.swp
.*sw?
.*sw?

View File

@ -175,7 +175,7 @@ Magnum in which way to construct a bay.::
--keypair-id testkey \
--external-network-id $NIC_ID \
--dns-nameserver 8.8.8.8 --flavor-id m1.small \
--docker-volume-size 5
--docker-volume-size 5 --coe kubernetes
Next create a bay. Use the baymodel UUID as a template for bay creation.
This bay will result in one master kubernetes node and two minion nodes.::
@ -264,25 +264,16 @@ replicating data between one another.
Building and using a Swarm bay
==============================
First, we will need to reconfigure Magnum. We need to set 'cluster_coe' in
the 'k8s_heat' section to 'swarm' in the magnum.conf. After changing
magnum.conf restart magnum-api and magnum-conductor.::
sudo cat >> /etc/magnum/magnum.conf << END_CONFIG
[k8s_heat]
cluster_coe=swarm
END_CONFIG
Next, create a baymodel, it is very similar to the Kubernetes baymodel,
it is only missing some Kubernetes specific arguments.::
Create a baymodel. It is very similar to the Kubernetes baymodel,
it is only missing some Kubernetes specific arguments and uses 'swarm' as the
coe. ::
NIC_ID=$(neutron net-show public | awk '/ id /{print $4}')
magnum baymodel-create --name swarmbaymodel --image-id fedora-21-atomic-3 \
--keypair-id testkey \
--external-network-id $NIC_ID \
--dns-nameserver 8.8.8.8 --flavor-id m1.small
--dns-nameserver 8.8.8.8 --flavor-id m1.small \
--coe swarm
Finally, create the bay. Use the baymodel 'swarmbaymodel' as a template for
bay creation. This bay will result in one swarm manager node and two extra

View File

@ -42,12 +42,26 @@ class BayModel(base.APIBase):
between the internal object model and the API representation of a baymodel.
"""
_coe = None
def _get_coe(self):
return self._coe
def _set_coe(self, value):
if value and self._coe != value:
self._coe = value
elif value == wtypes.Unset:
self._coe = wtypes.Unset
uuid = types.uuid
"""Unique UUID for this baymodel"""
name = wtypes.text
"""The name of the bay model"""
coe = wsme.wsproperty(wtypes.text, _get_coe, _set_coe, mandatory=True)
"""The Container Orchestration Engine for this bay model"""
image_id = wtypes.text
"""The image name or UUID to use as a base image for this baymodel"""
@ -97,7 +111,7 @@ class BayModel(base.APIBase):
def _convert_with_links(baymodel, url, expand=True):
if not expand:
baymodel.unset_fields_except(['uuid', 'name', 'image_id',
'apiserver_port'])
'apiserver_port', 'coe'])
baymodel.links = [link.Link.make_link('self', url,
'baymodels', baymodel.uuid),
@ -128,6 +142,7 @@ class BayModel(base.APIBase):
docker_volume_size=25,
cluster_distro='fedora-atomic',
ssh_authorized_key='ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAB',
coe='kubernetes',
created_at=datetime.datetime.utcnow(),
updated_at=datetime.datetime.utcnow())
return cls._convert_with_links(sample, 'http://localhost:9511', expand)

View File

@ -29,10 +29,6 @@ from magnum.openstack.common import loopingcall
k8s_heat_opts = [
cfg.StrOpt('cluster_coe',
default='kubernetes',
help=_('Container Orchestration Environments are '
'kubernetes or swarm. ')),
cfg.IntOpt('max_attempts',
default=2000,
help=('Number of attempts to query the Heat stack for '
@ -57,12 +53,16 @@ cfg.CONF.register_opts(k8s_heat_opts, group='k8s_heat')
LOG = logging.getLogger(__name__)
def _extract_template_definition(context, bay):
def _get_baymodel(context, bay):
baymodel = objects.BayModel.get_by_uuid(context, bay.baymodel_id)
return baymodel
def _extract_template_definition(context, bay):
baymodel = _get_baymodel(context, bay)
cluster_distro = baymodel.cluster_distro
cluster_coe = cfg.CONF.k8s_heat.cluster_coe
definition = TDef.get_template_definition('vm',
cluster_distro,
cluster_coe = baymodel.coe
definition = TDef.get_template_definition('vm', cluster_distro,
cluster_coe)
return definition.extract_definition(baymodel, bay)
@ -107,11 +107,10 @@ def _update_stack(context, osc, bay):
def _update_stack_outputs(context, stack, bay):
baymodel = objects.BayModel.get_by_uuid(context, bay.baymodel_id)
baymodel = _get_baymodel(context, bay)
cluster_distro = baymodel.cluster_distro
cluster_coe = cfg.CONF.k8s_heat.cluster_coe
definition = TDef.get_template_definition('vm',
cluster_distro,
cluster_coe = baymodel.coe
definition = TDef.get_template_definition('vm', cluster_distro,
cluster_coe)
return definition.update_outputs(stack, bay)
@ -222,6 +221,7 @@ class HeatPoller(object):
raise loopingcall.LoopingCallDone()
if (stack.stack_status in ['CREATE_COMPLETE', 'UPDATE_COMPLETE']):
_update_stack_outputs(self.context, stack, self.bay)
self.bay.status = stack.stack_status
self.bay.save()
raise loopingcall.LoopingCallDone()

View File

@ -0,0 +1,52 @@
# 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.
"""Add coe column to BayModel
Revision ID: 592131657ca1
Revises: 4956f03cabad
Create Date: 2015-04-17 14:20:17.620995
"""
# revision identifiers, used by Alembic.
revision = '592131657ca1'
down_revision = '4956f03cabad'
from alembic import op
from oslo_config import cfg
import sqlalchemy as sa
from magnum.openstack.common._i18n import _
k8s_heat_opts = [
cfg.StrOpt('cluster_coe',
default='kubernetes',
help=_('Container Orchestration Environments are '
'kubernetes or swarm. ')),
]
cfg.CONF.register_opts(k8s_heat_opts, group='k8s_heat')
def upgrade():
op.add_column('baymodel', sa.Column('coe', sa.String(length=255),
nullable=True))
baymodel = sa.sql.table('baymodel',
sa.sql.column('coe', sa.String(length=255)))
op.execute(
baymodel.update().values({'coe':
op.inline_literal(
cfg.CONF.k8s_heat.cluster_coe)})
)

View File

@ -169,6 +169,7 @@ class BayModel(Base):
docker_volume_size = Column(Integer())
ssh_authorized_key = Column(Text)
cluster_distro = Column(String(255))
coe = Column(String(255))
class Container(Base):

View File

@ -43,6 +43,7 @@ class BayModel(base.MagnumObject):
'docker_volume_size': obj_utils.int_or_none,
'ssh_authorized_key': obj_utils.str_or_none,
'cluster_distro': obj_utils.str_or_none,
'coe': obj_utils.str_or_none,
}
@staticmethod

View File

@ -67,6 +67,7 @@ class TestListBayModel(api_base.FunctionalTest):
self.assertIn('fixed_network', response)
self.assertIn('docker_volume_size', response)
self.assertIn('ssh_authorized_key', response)
self.assertIn('coe', response)
def test_get_one_by_name(self):
baymodel = obj_utils.create_test_baymodel(self.context)
@ -79,6 +80,7 @@ class TestListBayModel(api_base.FunctionalTest):
self.assertIn('external_network_id', response)
self.assertIn('fixed_network', response)
self.assertIn('docker_volume_size', response)
self.assertIn('coe', response)
def test_get_one_by_name_not_found(self):
response = self.get_json('/baymodels/not_found',
@ -110,6 +112,7 @@ class TestListBayModel(api_base.FunctionalTest):
self.assertIn('fixed_network', response['baymodels'][0])
self.assertIn('docker_volume_size', response['baymodels'][0])
self.assertIn('ssh_authorized_key', response['baymodels'][0])
self.assertIn('coe', response['baymodels'][0])
def test_detail_against_single(self):
baymodel = obj_utils.create_test_baymodel(self.context)
@ -177,7 +180,8 @@ class TestPatch(api_base.FunctionalTest):
'DYucqbeuM7nmJi+8Hb55y1xWoOZI'
'KMa71G5/4EOQxuQ/sgW965OOO2Hq'
'X8vjlQUnTK0HijrbSTLxp/9kazWW'
'FrfsdB8RtZBN digambar@magnum'
'FrfsdB8RtZBN digambar@magnum',
coe='swarm'
)
def test_update_not_found(self):
@ -219,6 +223,8 @@ class TestPatch(api_base.FunctionalTest):
response['docker_volume_size'])
self.assertEqual(self.baymodel.ssh_authorized_key,
response['ssh_authorized_key'])
self.assertEqual(self.baymodel.coe,
response['coe'])
def test_remove_singular(self):
baymodel = obj_utils.create_test_baymodel(self.context,
@ -243,6 +249,8 @@ class TestPatch(api_base.FunctionalTest):
response['docker_volume_size'])
self.assertEqual(self.baymodel.ssh_authorized_key,
response['ssh_authorized_key'])
self.assertEqual(self.baymodel.coe,
response['coe'])
def test_remove_non_existent_property_fail(self):
response = self.patch_json('/baymodels/%s' % self.baymodel.uuid,
@ -268,6 +276,8 @@ class TestPatch(api_base.FunctionalTest):
response['apiserver_port'])
self.assertEqual(self.baymodel.docker_volume_size,
response['docker_volume_size'])
self.assertEqual(self.baymodel.coe,
response['coe'])
def test_add_root_non_existent(self):
response = self.patch_json('/baymodels/%s' % self.baymodel.uuid,
@ -307,6 +317,8 @@ class TestPatch(api_base.FunctionalTest):
response['docker_volume_size'])
self.assertEqual(self.baymodel.ssh_authorized_key,
response['ssh_authorized_key'])
self.assertEqual(self.baymodel.coe,
response['coe'])
def test_remove_uuid(self):
response = self.patch_json('/baymodels/%s' % self.baymodel.uuid,

View File

@ -41,6 +41,7 @@ class TestBayK8sHeat(base.TestCase):
'docker_volume_size': 20,
'cluster_distro': 'fedora-atomic',
'ssh_authorized_key': 'ssh_authorized_key',
'coe': 'kubernetes',
'token': None,
}
self.bay_dict = {
@ -52,6 +53,15 @@ class TestBayK8sHeat(base.TestCase):
'node_count': 1,
}
@patch('magnum.objects.BayModel.get_by_uuid')
def test_get_baymodel(self, mock_objects_baymodel_get_by_uuid):
baymodel = objects.BayModel(self.context, **self.baymodel_dict)
mock_objects_baymodel_get_by_uuid.return_value = baymodel
bay = objects.Bay(self.context, **self.bay_dict)
fetched_baymodel = bay_k8s_heat._get_baymodel(self.context, bay)
self.assertEqual(baymodel, fetched_baymodel)
@patch('magnum.objects.BayModel.get_by_uuid')
def test_extract_template_definition(self,
mock_objects_baymodel_get_by_uuid):
@ -167,7 +177,7 @@ class TestBayK8sHeat(base.TestCase):
'master_flavor': 'master_flavor_id',
'number_of_minions': '1',
'fixed_network': 'private',
'docker_volume_size': 20
'docker_volume_size': 20,
}
self.assertEqual(expected, definition)
@ -192,7 +202,7 @@ class TestBayK8sHeat(base.TestCase):
'master_flavor': 'master_flavor_id',
'number_of_minions': '1',
'fixed_network': 'private',
'docker_volume_size': 20
'docker_volume_size': 20,
}
self.assertEqual(expected, definition)
@ -700,6 +710,9 @@ class TestHandler(db_base.DbTestCase):
def setUp(self):
super(TestHandler, self).setUp()
self.handler = bay_k8s_heat.Handler()
baymodel_dict = utils.get_test_baymodel()
self.baymodel = objects.BayModel(self.context, **baymodel_dict)
self.baymodel.create()
bay_dict = utils.get_test_bay(node_count=1)
self.bay = objects.Bay(self.context, **bay_dict)
self.bay.create()
@ -775,6 +788,7 @@ class TestBayK8sHeatSwarm(base.TestCase):
'external_network_id': 'external_network_id',
'fixed_network': '10.2.0.0/22',
'cluster_distro': 'fedora-atomic',
'coe': 'swarm'
}
self.bay_dict = {
'id': 1,
@ -791,7 +805,6 @@ class TestBayK8sHeatSwarm(base.TestCase):
@patch('magnum.objects.BayModel.get_by_uuid')
def test_extract_template_definition_all_values(self,
mock_objects_baymodel_get_by_uuid):
cfg.CONF.set_override('cluster_coe', 'swarm', group='k8s_heat')
baymodel = objects.BayModel(self.context, **self.baymodel_dict)
mock_objects_baymodel_get_by_uuid.return_value = baymodel
bay = objects.Bay(self.context, **self.bay_dict)
@ -815,7 +828,6 @@ class TestBayK8sHeatSwarm(base.TestCase):
@patch('magnum.objects.BayModel.get_by_uuid')
def test_extract_template_definition_only_required(self,
mock_objects_baymodel_get_by_uuid):
cfg.CONF.set_override('cluster_coe', 'swarm', group='k8s_heat')
cfg.CONF.set_override('public_swarm_discovery', False, group='bay')
cfg.CONF.set_override('swarm_discovery_url_format',
'test_discovery', group='bay')

View File

@ -44,6 +44,7 @@ def get_test_baymodel(**kw):
'KMa71G5/4EOQxuQ/sgW965OOO2Hq'
'X8vjlQUnTK0HijrbSTLxp/9kazWW'
'FrfsdB8RtZBN digambar@magnum'),
'coe': kw.get('coe', 'swarm'),
'created_at': kw.get('created_at'),
'updated_at': kw.get('updated_at'),
}