Update service manifest parsing according to v1beta3

Now that Kubernetes 0.15.0 release is supported and it has
v1beta3, the manifest structure has changed from v1beta1 to
v1beta3. This change implements the v1beta3 manifest parsing
logic for service resource of Kubernetes.

Change-Id: I1200473f91118eaa48b1cec386f30cf8a50708b5
Partially-Implements: blueprint python-k8sclient
This commit is contained in:
Madhuri Kumari 2015-04-29 06:27:46 +00:00 committed by Steven Dake
parent 2704710e28
commit 08a27f1c0f
10 changed files with 101 additions and 43 deletions

View File

@ -37,7 +37,7 @@ class ServicePatchType(v1_base.K8sPatchType):
@staticmethod
def internal_attrs():
defaults = v1_base.K8sPatchType.internal_attrs()
return defaults + ['/selector', '/port', '/ip']
return defaults + ['/selector', '/ports', '/ip']
class Service(v1_base.K8sResourceBase):
@ -51,7 +51,7 @@ class Service(v1_base.K8sResourceBase):
ip = wtypes.text
"""IP of this service"""
port = wsme.wsattr(wtypes.IntegerType(), readonly=True)
ports = wsme.wsattr([{wtypes.text: wtypes.IntegerType()}], readonly=True)
"""Port of this service"""
links = wsme.wsattr([link.Link], readonly=True)
@ -72,7 +72,7 @@ class Service(v1_base.K8sResourceBase):
def _convert_with_links(service, url, expand=True):
if not expand:
service.unset_fields_except(['uuid', 'name', 'bay_uuid', 'labels',
'selector', 'ip', 'port'])
'selector', 'ip', 'ports'])
service.links = [link.Link.make_link('self', url,
'services', service.uuid),
@ -95,20 +95,34 @@ class Service(v1_base.K8sResourceBase):
labels={'label1': 'foo'},
selector={'label1': 'foo'},
ip='172.17.2.2',
port=80,
ports=[
{
"port": 88,
"targetPort": 6379,
"protocol": "TCP"
}
],
manifest_url='file:///tmp/rc.yaml',
manifest='''{
"id": "service_foo",
"kind": "Service",
"apiVersion": "v1beta1",
"port": 88,
"selector": {
"bar": "foo"
"metadata": {
"name": "test",
"labels": {
"key": "value"
}
},
"labels": {
"bar": "foo"
"spec": {
"ports": [
{
"port": 88,
"targetPort": 6379,
"protocol": "TCP"
}
],
"selector": {
"bar": "foo"
}
}
}''',
}''',
created_at=datetime.datetime.utcnow(),
updated_at=datetime.datetime.utcnow())
return cls._convert_with_links(sample, 'http://localhost:9511', expand)
@ -119,16 +133,20 @@ class Service(v1_base.K8sResourceBase):
except ValueError as e:
raise exception.InvalidParameterValue(message=str(e))
try:
self.name = manifest["id"]
except KeyError:
self.name = manifest["metadata"]["name"]
except (KeyError, TypeError):
raise exception.InvalidParameterValue(
"'id' can't be empty in manifest.")
if "port" in manifest:
self.port = manifest["port"]
if "selector" in manifest:
self.selector = manifest["selector"]
if "labels" in manifest:
self.labels = manifest["labels"]
"Field metadata['name'] can't be empty in manifest.")
try:
self.ports = manifest["spec"]["ports"][:]
except (KeyError, TypeError):
raise exception.InvalidParameterValue(
"Field spec['ports'] can't be empty in manifest.")
if "selector" in manifest["spec"]:
self.selector = manifest["spec"]["selector"]
if "labels" in manifest["metadata"]:
self.labels = manifest["metadata"]["labels"]
class ServiceCollection(collection.Collection):

View File

@ -0,0 +1,32 @@
# 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 service port
Revision ID: 2b5f24dd95de
Revises: 592131657ca1
Create Date: 2015-04-29 05:52:52.204095
"""
# revision identifiers, used by Alembic.
revision = '2b5f24dd95de'
down_revision = '3b6c4c42adb4'
from alembic import op
from magnum.db.sqlalchemy import models
def upgrade():
op.alter_column('service', 'port',
new_column_name='ports',
existing_type=models.JSONEncodedList())

View File

@ -704,8 +704,8 @@ class Connection(api.Connection):
query = query.filter_by(name=filters['name'])
if 'ip' in filters:
query = query.filter_by(ip=filters['ip'])
if 'port' in filters:
query = query.filter_by(port=filters['port'])
if 'ports' in filters:
query = query.filter_by(ports=filters['ports'])
return query

View File

@ -244,7 +244,7 @@ class Service(Base):
labels = Column(JSONEncodedDict)
selector = Column(JSONEncodedDict)
ip = Column(String(36))
port = Column(Integer())
ports = Column(JSONEncodedList)
project_id = Column(String(255))
user_id = Column(String(255))

View File

@ -34,7 +34,7 @@ class Service(base.MagnumObject):
'labels': obj_utils.dict_or_none,
'selector': obj_utils.dict_or_none,
'ip': obj_utils.str_or_none,
'port': obj_utils.int_or_none,
'ports': obj_utils.list_or_none,
'manifest_url': obj_utils.str_or_none,
'manifest': obj_utils.str_or_none,
}

View File

@ -49,7 +49,7 @@ class TestListService(api_base.FunctionalTest):
def _assert_service_fields(self, service):
service_fields = ['name', 'bay_uuid', 'name', 'labels', 'selector',
'ip', 'port']
'ip', 'ports']
for field in service_fields:
self.assertIn(field, service)

View File

@ -67,17 +67,25 @@ def service_post_data(**kw):
service = utils.get_test_service(**kw)
if 'manifest' not in service:
service['manifest'] = '''{
"id": "service_foo",
"kind": "Service",
"apiVersion": "v1beta1",
"port": 88,
"selector": {
"bar": "foo"
"metadata": {
"name": "test",
"labels": {
"key": "value"
}
},
"labels": {
"bar": "foo"
"spec": {
"ports": [
{
"port": 88,
"targetPort": 6379,
"protocol": "TCP"
}
],
"selector": {
"bar": "foo"
}
}
}'''
}'''
internal = service_controller.ServicePatchType.internal_attrs()
return remove_internal(service, internal)

View File

@ -91,11 +91,11 @@ class DbServiceTestCase(base.DbTestCase):
service1 = utils.create_test_service(name='service-one',
uuid=magnum_utils.generate_uuid(),
bay_uuid=bay1['uuid'],
port=8000)
ports=[{'port': 8000}])
service2 = utils.create_test_service(name='service-two',
uuid=magnum_utils.generate_uuid(),
bay_uuid=bay2['uuid'],
port=8001)
ports=[{'port': 8001}])
res = self.dbapi.get_service_list(self.context,
filters={'bay_uuid': bay1['uuid']})
@ -114,11 +114,11 @@ class DbServiceTestCase(base.DbTestCase):
self.assertEqual([], [r.id for r in res])
res = self.dbapi.get_service_list(self.context,
filters={'port': 8000})
filters={'ports': [{'port': 8000}]})
self.assertEqual([service1.id], [r.id for r in res])
res = self.dbapi.get_service_list(self.context,
filters={'port': 8001})
filters={'ports': [{'port': 8001}]})
self.assertEqual([service2.id], [r.id for r in res])
def test_get_service_list_bay_not_exist(self):

View File

@ -126,7 +126,7 @@ def get_test_service(**kw):
'labels': kw.get('labels', {'name': 'foo'}),
'selector': kw.get('selector', {'name': 'foo'}),
'ip': kw.get('ip', '172.17.2.2'),
'port': kw.get('port', 80),
'ports': kw.get('ports', [{'port': 80}]),
'created_at': kw.get('created_at'),
'updated_at': kw.get('updated_at'),
}

View File

@ -95,12 +95,12 @@ class TestServiceObject(base.DbTestCase):
with mock.patch.object(self.dbapi, 'update_service',
autospec=True) as mock_update_service:
service = objects.Service.get_by_uuid(self.context, uuid)
service.port = 4567
service.ports = [{'port': 4567}]
service.save()
mock_get_service.assert_called_once_with(self.context, uuid)
mock_update_service.assert_called_once_with(
uuid, {'port': 4567})
uuid, {'ports': [{'port': 4567}]})
self.assertEqual(self.context, service._context)
def test_refresh(self):