Adds labels support to baymodels
Adds labels to the following: 1. api baymodel attribute 2. conductor template definitions and entrypoints 3. a new column to the baymodel db 4. objects. Note: Updates baymodel object version 5. Tests Partially-Implements: blueprint extend-api-network-attributes Partially-Implements: blueprint extend-baymodel-net-attributes Partially-Implements: blueprint conductor-template-net-update Change-Id: I49f9c7df28f806cdedb3a382b1cb41bc48ff4e90
This commit is contained in:
parent
c0ad7c376e
commit
e01881726b
|
@ -118,6 +118,9 @@ class BayModel(base.APIBase):
|
|||
registry_enabled = wsme.wsattr(types.boolean, default=False)
|
||||
"""Indicates whether the docker registry is enabled"""
|
||||
|
||||
labels = wtypes.DictType(str, str)
|
||||
"""One or more key/value pairs"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.fields = []
|
||||
for field in objects.BayModel.fields:
|
||||
|
@ -167,6 +170,7 @@ class BayModel(base.APIBase):
|
|||
http_proxy='http://proxy.com:123',
|
||||
https_proxy='https://proxy.com:123',
|
||||
no_proxy='192.168.0.1,192.168.0.2,192.168.0.3',
|
||||
labels={'key1': 'val1', 'key2': 'val2'},
|
||||
created_at=datetime.datetime.utcnow(),
|
||||
updated_at=datetime.datetime.utcnow())
|
||||
return cls._convert_with_links(sample, 'http://localhost:9511', expand)
|
||||
|
|
|
@ -407,6 +407,8 @@ class AtomicK8sTemplateDefinition(BaseTemplateDefinition):
|
|||
|
||||
def get_params(self, context, baymodel, bay, **kwargs):
|
||||
extra_params = kwargs.pop('extra_params', {})
|
||||
label_list = ['flannel_network_cidr', 'flannel_use_vxlan',
|
||||
'flannel_network_subnetlen']
|
||||
scale_mgr = kwargs.pop('scale_manager', None)
|
||||
if scale_mgr:
|
||||
hosts = self.get_output('kube_minions')
|
||||
|
@ -415,6 +417,9 @@ class AtomicK8sTemplateDefinition(BaseTemplateDefinition):
|
|||
|
||||
extra_params['discovery_url'] = self.get_discovery_url(bay)
|
||||
|
||||
for label in label_list:
|
||||
extra_params[label] = baymodel.labels.get(label)
|
||||
|
||||
return super(AtomicK8sTemplateDefinition,
|
||||
self).get_params(context, baymodel, bay,
|
||||
extra_params=extra_params,
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
# 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 labels column to baymodel table
|
||||
|
||||
Revision ID: 1481f5b560dd
|
||||
Revises: 3be65537a94a
|
||||
Create Date: 2015-09-02 22:34:07.590142
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '1481f5b560dd'
|
||||
down_revision = '3be65537a94a'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column('baymodel', sa.Column('labels',
|
||||
sa.Text(), nullable=True))
|
|
@ -316,6 +316,8 @@ class Connection(api.Connection):
|
|||
query = query.filter_by(project_id=filters['project_id'])
|
||||
if 'user_id' in filters:
|
||||
query = query.filter_by(user_id=filters['user_id'])
|
||||
if 'labels' in filters:
|
||||
query = query.filter_by(labels=filters['labels'])
|
||||
|
||||
return query
|
||||
|
||||
|
|
|
@ -171,6 +171,7 @@ class BayModel(Base):
|
|||
https_proxy = Column(String(255))
|
||||
no_proxy = Column(String(255))
|
||||
registry_enabled = Column(Boolean, default=False)
|
||||
labels = Column(JSONEncodedDict)
|
||||
|
||||
|
||||
class Container(Base):
|
||||
|
|
|
@ -27,7 +27,8 @@ class BayModel(base.MagnumPersistentObject, base.MagnumObject,
|
|||
# Version 1.0: Initial version
|
||||
# Version 1.1: Add 'registry_enabled' field
|
||||
# Version 1.2: Added 'network_driver' field
|
||||
VERSION = '1.2'
|
||||
# Version 1.3: Added 'labels' attribute
|
||||
VERSION = '1.3'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
|
||||
|
@ -53,7 +54,8 @@ class BayModel(base.MagnumPersistentObject, base.MagnumObject,
|
|||
'http_proxy': fields.StringField(nullable=True),
|
||||
'https_proxy': fields.StringField(nullable=True),
|
||||
'no_proxy': fields.StringField(nullable=True),
|
||||
'registry_enabled': fields.BooleanField(default=False)
|
||||
'registry_enabled': fields.BooleanField(default=False),
|
||||
'labels': fields.DictOfStringsField(nullable=True)
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -61,6 +61,7 @@ class TestListBayModel(api_base.FunctionalTest):
|
|||
self.assertNotIn('http_proxy', response['baymodels'][0])
|
||||
self.assertNotIn('https_proxy', response['baymodels'][0])
|
||||
self.assertNotIn('no_proxy', response['baymodels'][0])
|
||||
self.assertNotIn('labels', response['baymodels'][0])
|
||||
|
||||
def test_get_one(self):
|
||||
baymodel = obj_utils.create_test_baymodel(self.context)
|
||||
|
@ -79,6 +80,7 @@ class TestListBayModel(api_base.FunctionalTest):
|
|||
self.assertIn('http_proxy', response)
|
||||
self.assertIn('https_proxy', response)
|
||||
self.assertIn('no_proxy', response)
|
||||
self.assertIn('labels', response)
|
||||
|
||||
def test_get_one_by_name(self):
|
||||
baymodel = obj_utils.create_test_baymodel(self.context)
|
||||
|
@ -96,6 +98,7 @@ class TestListBayModel(api_base.FunctionalTest):
|
|||
self.assertIn('http_proxy', response)
|
||||
self.assertIn('https_proxy', response)
|
||||
self.assertIn('https_proxy', response)
|
||||
self.assertIn('labels', response)
|
||||
|
||||
def test_get_one_by_name_not_found(self):
|
||||
response = self.get_json(
|
||||
|
@ -139,7 +142,7 @@ class TestListBayModel(api_base.FunctionalTest):
|
|||
for key in ("flavor_id", "master_flavor_id", "dns_nameserver",
|
||||
"keypair_id", "external_network_id", "fixed_network",
|
||||
"docker_volume_size", "ssh_authorized_key", "coe",
|
||||
"http_proxy", "https_proxy", "no_proxy",
|
||||
"http_proxy", "https_proxy", "no_proxy", "labels",
|
||||
"network_driver"):
|
||||
self.assertIn(key, response['baymodels'][0])
|
||||
|
||||
|
@ -157,7 +160,7 @@ class TestListBayModel(api_base.FunctionalTest):
|
|||
self.assertEqual(bm_list[-1].uuid, response['baymodels'][0]['uuid'])
|
||||
for key in ("flavor_id", "master_flavor_id", "dns_nameserver",
|
||||
"keypair_id", "external_network_id", "fixed_network",
|
||||
"network_driver", "docker_volume_size",
|
||||
"network_driver", "docker_volume_size", "labels",
|
||||
"ssh_authorized_key", "coe"):
|
||||
self.assertIn(key, response['baymodels'][0])
|
||||
self.assertIn('flavor_id', response['baymodels'][0])
|
||||
|
@ -243,7 +246,8 @@ class TestPatch(api_base.FunctionalTest):
|
|||
'KMa71G5/4EOQxuQ/sgW965OOO2Hq'
|
||||
'X8vjlQUnTK0HijrbSTLxp/9kazWW'
|
||||
'FrfsdB8RtZBN digambar@magnum',
|
||||
coe='swarm'
|
||||
coe='swarm',
|
||||
labels={'key1': 'val1', 'key2': 'val2'}
|
||||
)
|
||||
|
||||
def test_update_not_found(self):
|
||||
|
@ -295,6 +299,8 @@ class TestPatch(api_base.FunctionalTest):
|
|||
response['https_proxy'])
|
||||
self.assertEqual(self.baymodel.no_proxy,
|
||||
response['no_proxy'])
|
||||
self.assertEqual(self.baymodel.labels,
|
||||
response['labels'])
|
||||
|
||||
def test_remove_singular(self):
|
||||
baymodel = obj_utils.create_test_baymodel(self.context,
|
||||
|
@ -329,6 +335,8 @@ class TestPatch(api_base.FunctionalTest):
|
|||
response['https_proxy'])
|
||||
self.assertEqual(self.baymodel.no_proxy,
|
||||
response['no_proxy'])
|
||||
self.assertEqual(self.baymodel.labels,
|
||||
response['labels'])
|
||||
|
||||
def test_remove_non_existent_property_fail(self):
|
||||
response = self.patch_json('/baymodels/%s' % self.baymodel.uuid,
|
||||
|
@ -359,6 +367,8 @@ class TestPatch(api_base.FunctionalTest):
|
|||
response['docker_volume_size'])
|
||||
self.assertEqual(self.baymodel.coe,
|
||||
response['coe'])
|
||||
self.assertEqual(self.baymodel.labels,
|
||||
response['labels'])
|
||||
|
||||
def test_add_root_non_existent(self):
|
||||
response = self.patch_json(
|
||||
|
@ -409,6 +419,8 @@ class TestPatch(api_base.FunctionalTest):
|
|||
response['https_proxy'])
|
||||
self.assertEqual(self.baymodel.no_proxy,
|
||||
response['no_proxy'])
|
||||
self.assertEqual(self.baymodel.labels,
|
||||
response['labels'])
|
||||
|
||||
def test_remove_uuid(self):
|
||||
response = self.patch_json('/baymodels/%s' % self.baymodel.uuid,
|
||||
|
@ -501,7 +513,7 @@ class TestPost(api_base.FunctionalTest):
|
|||
"dns_nameserver", "keypair_id", "external_network_id",
|
||||
"cluster_distro", "fixed_network", "apiserver_port",
|
||||
"docker_volume_size", "http_proxy", "https_proxy",
|
||||
"no_proxy", "network_driver"]
|
||||
"no_proxy", "network_driver", "labels"]
|
||||
for field in fields:
|
||||
self._create_baymodel_raises_app_error(**{field: 'i' * 256})
|
||||
|
||||
|
@ -509,7 +521,7 @@ class TestPost(api_base.FunctionalTest):
|
|||
fields = ["uuid", "name", "image_id", "flavor_id", "master_flavor_id",
|
||||
"dns_nameserver", "keypair_id", "external_network_id",
|
||||
"cluster_distro", "fixed_network", "apiserver_port",
|
||||
"docker_volume_size", "ssh_authorized_key",
|
||||
"docker_volume_size", "ssh_authorized_key", "labels",
|
||||
"http_proxy", "https_proxy", "no_proxy", "network_driver"]
|
||||
for field in fields:
|
||||
self._create_baymodel_raises_app_error(**{field: ''})
|
||||
|
@ -531,6 +543,24 @@ class TestPost(api_base.FunctionalTest):
|
|||
self._create_baymodel_raises_app_error(apiserver_port=1023)
|
||||
self._create_baymodel_raises_app_error(apiserver_port='not an int')
|
||||
|
||||
@mock.patch.object(api_baymodel.BayModelsController, '_get_image_data')
|
||||
@mock.patch.object(api_baymodel.BayModelsController,
|
||||
'check_keypair_exists')
|
||||
def test_create_baymodel_with_labels(self, mock_keypair_exists,
|
||||
mock_image_data):
|
||||
with mock.patch.object(self.dbapi, 'create_baymodel',
|
||||
wraps=self.dbapi.create_baymodel) as cc_mock:
|
||||
mock_keypair_exists.return_value = None
|
||||
mock_image_data.return_value = {'name': 'mock_name',
|
||||
'os_distro': 'fedora-atomic'}
|
||||
bdict = apiutils.baymodel_post_data(labels={'key1': 'val1',
|
||||
'key2': 'val2'})
|
||||
response = self.post_json('/baymodels', bdict)
|
||||
self.assertEqual(bdict['labels'],
|
||||
response.json['labels'])
|
||||
cc_mock.assert_called_once_with(mock.ANY)
|
||||
self.assertNotIn('id', cc_mock.call_args[0][0])
|
||||
|
||||
@mock.patch.object(api_baymodel.BayModelsController, '_get_image_data')
|
||||
@mock.patch.object(api_baymodel.BayModelsController,
|
||||
'check_keypair_exists')
|
||||
|
|
|
@ -48,6 +48,9 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||
'http_proxy': 'http_proxy',
|
||||
'https_proxy': 'https_proxy',
|
||||
'no_proxy': 'no_proxy',
|
||||
'labels': {'flannel_network_cidr': '10.101.0.0/16',
|
||||
'flannel_network_subnetlen': '26',
|
||||
'flannel_use_vxlan': 'yes'},
|
||||
}
|
||||
self.bay_dict = {
|
||||
'baymodel_id': 'xx-xx-xx-xx',
|
||||
|
@ -98,6 +101,9 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||
'node_count': 'number_of_minions',
|
||||
'master_count': 'number_of_masters',
|
||||
'discovery_url': 'discovery_url',
|
||||
'labels': {'flannel_network_cidr': '10.101.0.0/16',
|
||||
'flannel_network_subnetlen': '26',
|
||||
'flannel_use_vxlan': 'yes'},
|
||||
'http_proxy': 'http_proxy',
|
||||
'https_proxy': 'https_proxy',
|
||||
'no_proxy': 'no_proxy',
|
||||
|
@ -115,6 +121,9 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||
'fixed_network_cidr': '10.20.30.0/24',
|
||||
'docker_volume_size': 20,
|
||||
'discovery_url': 'https://discovery.etcd.io/test',
|
||||
'flannel_network_cidr': '10.101.0.0/16',
|
||||
'flannel_network_subnetlen': '26',
|
||||
'flannel_use_vxlan': 'yes',
|
||||
'http_proxy': 'http_proxy',
|
||||
'https_proxy': 'https_proxy',
|
||||
'no_proxy': 'no_proxy',
|
||||
|
@ -163,6 +172,9 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||
'http_proxy': 'http_proxy',
|
||||
'https_proxy': 'https_proxy',
|
||||
'no_proxy': 'no_proxy',
|
||||
'flannel_network_cidr': '10.101.0.0/16',
|
||||
'flannel_network_subnetlen': '26',
|
||||
'flannel_use_vxlan': 'yes',
|
||||
}
|
||||
self.assertEqual(expected, definition)
|
||||
|
||||
|
@ -205,6 +217,9 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||
'http_proxy': 'http_proxy',
|
||||
'https_proxy': 'https_proxy',
|
||||
'no_proxy': 'no_proxy',
|
||||
'flannel_network_cidr': '10.101.0.0/16',
|
||||
'flannel_network_subnetlen': '26',
|
||||
'flannel_use_vxlan': 'yes',
|
||||
}
|
||||
self.assertEqual(expected, definition)
|
||||
|
||||
|
@ -286,7 +301,10 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||
'discovery_url': 'https://discovery.etcd.io/test',
|
||||
'http_proxy': 'http_proxy',
|
||||
'https_proxy': 'https_proxy',
|
||||
'no_proxy': 'no_proxy'
|
||||
'no_proxy': 'no_proxy',
|
||||
'flannel_network_cidr': '10.101.0.0/16',
|
||||
'flannel_network_subnetlen': '26',
|
||||
'flannel_use_vxlan': 'yes',
|
||||
}
|
||||
self.assertIn('token', definition)
|
||||
del definition['token']
|
||||
|
@ -353,7 +371,10 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||
'discovery_url': 'https://address/token',
|
||||
'http_proxy': 'http_proxy',
|
||||
'https_proxy': 'https_proxy',
|
||||
'no_proxy': 'no_proxy'
|
||||
'no_proxy': 'no_proxy',
|
||||
'flannel_network_cidr': '10.101.0.0/16',
|
||||
'flannel_network_subnetlen': '26',
|
||||
'flannel_use_vxlan': 'yes',
|
||||
}
|
||||
self.assertEqual(expected, definition)
|
||||
reqget.assert_called_once_with('http://etcd/test?size=1')
|
||||
|
|
|
@ -184,6 +184,11 @@ class AtomicK8sTemplateDefinitionTestCase(base.TestCase):
|
|||
removal_nodes = ['node1', 'node2']
|
||||
mock_scale_manager.get_removal_nodes.return_value = removal_nodes
|
||||
mock_get_discovery_url.return_value = 'fake_discovery_url'
|
||||
|
||||
flannel_cidr = mock_baymodel.labels.get('flannel_network_cidr')
|
||||
flannel_subnet = mock_baymodel.labels.get('flannel_network_subnetlen')
|
||||
flannel_vxlan = mock_baymodel.labels.get('flannel_use_vxlan')
|
||||
|
||||
k8s_def = tdef.AtomicK8sTemplateDefinition()
|
||||
|
||||
k8s_def.get_params(mock_context, mock_baymodel, mock_bay,
|
||||
|
@ -191,7 +196,10 @@ class AtomicK8sTemplateDefinitionTestCase(base.TestCase):
|
|||
|
||||
expected_kwargs = {'extra_params': {
|
||||
'minions_to_remove': removal_nodes,
|
||||
'discovery_url': 'fake_discovery_url'}}
|
||||
'discovery_url': 'fake_discovery_url',
|
||||
'flannel_network_cidr': flannel_cidr,
|
||||
'flannel_use_vxlan': flannel_subnet,
|
||||
'flannel_network_subnetlen': flannel_vxlan}}
|
||||
mock_get_params.assert_called_once_with(mock_context, mock_baymodel,
|
||||
mock_bay, **expected_kwargs)
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ def get_test_baymodel(**kw):
|
|||
'coe': kw.get('coe', 'swarm'),
|
||||
'created_at': kw.get('created_at'),
|
||||
'updated_at': kw.get('updated_at'),
|
||||
'labels': kw.get('labels', {'key1': 'val1', 'key2': 'val2'}),
|
||||
'http_proxy': kw.get('http_proxy', 'fake_http_proxy'),
|
||||
'https_proxy': kw.get('https_proxy', 'fake_https_proxy'),
|
||||
'no_proxy': kw.get('no_proxy', 'fake_no_proxy'),
|
||||
|
|
|
@ -426,7 +426,7 @@ class _TestObject(object):
|
|||
object_data = {
|
||||
'Bay': '1.0-35edde13ad178e9419e7ea8b6d580bcd',
|
||||
'BayLock': '1.0-7d1eb08cf2070523bd210369c7a2e076',
|
||||
'BayModel': '1.2-b08e888342cc84d7c709193529b92c6f',
|
||||
'BayModel': '1.3-369d7b7f05720780ae4f6c5d983e8c3e',
|
||||
'Certificate': '1.0-2aff667971b85c1edf8d15684fd7d5e2',
|
||||
'Container': '1.0-e12affbba5f8a748882a3ae98aced282',
|
||||
'MyObj': '1.0-b43567e512438205e32f4e95ca616697',
|
||||
|
|
Loading…
Reference in New Issue