diff --git a/magnum/api/controllers/v1/bay.py b/magnum/api/controllers/v1/bay.py index b658f06739..4610ec9e34 100644 --- a/magnum/api/controllers/v1/bay.py +++ b/magnum/api/controllers/v1/bay.py @@ -111,6 +111,13 @@ class Bay(base.APIBase): api_address = wsme.wsattr(wtypes.text, readonly=True) """Api address of cluster master node""" + coe_version = wsme.wsattr(wtypes.text, readonly=True) + """Version of the COE software currently running in this cluster. + Example: swarm version or kubernetes version.""" + + container_version = wsme.wsattr(wtypes.text, readonly=True) + """Version of the container software. Example: docker version.""" + node_addresses = wsme.wsattr([wtypes.text], readonly=True) """IP addresses of cluster agent nodes""" @@ -165,7 +172,9 @@ class Bay(base.APIBase): api_address='172.24.4.3', node_addresses=['172.24.4.4', '172.24.4.5'], created_at=timeutils.utcnow(), - updated_at=timeutils.utcnow()) + updated_at=timeutils.utcnow(), + coe_version=None, + container_version=None) return cls._convert_with_links(sample, 'http://localhost:9511', expand) @@ -365,6 +374,8 @@ class BaysController(base.Controller): # bay if the name is not spcified by user. name = bay_dict.get('name') or self._generate_name_for_bay(context) bay_dict['name'] = name + bay_dict['coe_version'] = None + bay_dict['container_version'] = None new_bay = objects.Bay(context, **bay_dict) new_bay.uuid = uuid.uuid4() diff --git a/magnum/api/controllers/v1/cluster.py b/magnum/api/controllers/v1/cluster.py index 7acc56ebf8..3b4a031864 100644 --- a/magnum/api/controllers/v1/cluster.py +++ b/magnum/api/controllers/v1/cluster.py @@ -121,6 +121,13 @@ class Cluster(base.APIBase): api_address = wsme.wsattr(wtypes.text, readonly=True) """Api address of cluster master node""" + coe_version = wsme.wsattr(wtypes.text, readonly=True) + """Version of the COE software currently running in this cluster. + Example: swarm version or kubernetes version.""" + + container_version = wsme.wsattr(wtypes.text, readonly=True) + """Version of the container software. Example: docker version.""" + node_addresses = wsme.wsattr([wtypes.text], readonly=True) """IP addresses of cluster agent nodes""" @@ -198,7 +205,9 @@ class Cluster(base.APIBase): api_address='172.24.4.3', node_addresses=['172.24.4.4', '172.24.4.5'], created_at=timeutils.utcnow(), - updated_at=timeutils.utcnow()) + updated_at=timeutils.utcnow(), + coe_version=None, + container_version=None) return cls._convert_with_links(sample, 'http://localhost:9511', expand) def as_dict(self): @@ -405,6 +414,8 @@ class ClustersController(base.Controller): name = cluster_dict.get('name') or \ self._generate_name_for_cluster(context) cluster_dict['name'] = name + cluster_dict['coe_version'] = None + cluster_dict['container_version'] = None new_cluster = objects.Bay(context, **cluster_dict) new_cluster.uuid = uuid.uuid4() diff --git a/magnum/conductor/handlers/bay_conductor.py b/magnum/conductor/handlers/bay_conductor.py index c7856c9e1c..405301df0b 100644 --- a/magnum/conductor/handlers/bay_conductor.py +++ b/magnum/conductor/handlers/bay_conductor.py @@ -19,6 +19,7 @@ from heatclient import exc from oslo_config import cfg from oslo_log import log as logging from oslo_service import loopingcall +from oslo_utils import importutils from pycadf import cadftaxonomy as taxonomy import six @@ -360,8 +361,27 @@ class HeatPoller(object): self.bay.node_count = stack.parameters[stack_nc_param] self.bay.save() + def get_version_info(self, stack): + stack_param = self.template_def.get_heat_param( + bay_attr='coe_version') + 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) + + version_module_path = tdef.driver_module_path+'.version' + try: + ver = importutils.import_module(version_module_path) + container_version = ver.container_version + except Exception: + container_version = None + 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.get_version_info(stack) self._sync_bay_status(stack) def _bay_failed(self, stack): diff --git a/magnum/db/sqlalchemy/alembic/versions/fcb4efee8f8b_add_version_info_to_bay.py b/magnum/db/sqlalchemy/alembic/versions/fcb4efee8f8b_add_version_info_to_bay.py new file mode 100644 index 0000000000..f58ff70e5c --- /dev/null +++ b/magnum/db/sqlalchemy/alembic/versions/fcb4efee8f8b_add_version_info_to_bay.py @@ -0,0 +1,34 @@ +# 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 version info to bay + +Revision ID: fcb4efee8f8b +Revises: b1f612248cab +Create Date: 2016-08-22 15:04:32.256811 + +""" + +# revision identifiers, used by Alembic. +revision = 'fcb4efee8f8b' +down_revision = 'b1f612248cab' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('bay', + sa.Column('coe_version', sa.String(length=255), + nullable=True)) + op.add_column('bay', + sa.Column('container_version', sa.String(length=255), + nullable=True)) diff --git a/magnum/db/sqlalchemy/models.py b/magnum/db/sqlalchemy/models.py index de2cb16a4f..1eebb5423e 100644 --- a/magnum/db/sqlalchemy/models.py +++ b/magnum/db/sqlalchemy/models.py @@ -129,6 +129,8 @@ class Bay(Base): trustee_user_id = Column(String(255)) # TODO(wanghua): encrypt trustee_password in db trustee_password = Column(String(255)) + coe_version = Column(String(255)) + container_version = Column(String(255)) # (yuanying) if we use barbican, # cert_ref size is determined by below format # * http(s)://${DOMAIN_NAME}/v1/containers/${UUID} diff --git a/magnum/drivers/common/template_def.py b/magnum/drivers/common/template_def.py index 1f6f9b28cc..e205e1f625 100644 --- a/magnum/drivers/common/template_def.py +++ b/magnum/drivers/common/template_def.py @@ -317,6 +317,10 @@ class TemplateDefinition(object): for output in self.output_mappings: output.set_output(stack, baymodel, bay) + @abc.abstractproperty + def driver_module_path(self): + pass + @abc.abstractproperty def template_path(self): pass @@ -348,6 +352,10 @@ class BaseTemplateDefinition(TemplateDefinition): self.add_parameter('number_of_masters', bay_attr='master_count') + @property + def driver_module_path(self): + pass + @abc.abstractproperty def template_path(self): pass diff --git a/magnum/drivers/k8s_coreos_v1/template_def.py b/magnum/drivers/k8s_coreos_v1/template_def.py index df2998d5d5..17addef877 100644 --- a/magnum/drivers/k8s_coreos_v1/template_def.py +++ b/magnum/drivers/k8s_coreos_v1/template_def.py @@ -73,6 +73,8 @@ class K8sTemplateDefinition(template_def.BaseTemplateDefinition): param_type=str) self.add_parameter('insecure_registry_url', baymodel_attr='insecure_registry') + self.add_parameter('kube_version', + bay_attr='coe_version') self.add_output('api_address', bay_attr='api_address', @@ -133,6 +135,10 @@ class CoreOSK8sTemplateDefinition(K8sTemplateDefinition): else: return ['../../common/templates/environments/no_master_lb.yaml'] + @property + def driver_module_path(self): + return __name__[:__name__.rindex('.')] + @property def template_path(self): return os.path.join(os.path.dirname(os.path.realpath(__file__)), diff --git a/magnum/drivers/k8s_coreos_v1/version.py b/magnum/drivers/k8s_coreos_v1/version.py new file mode 100644 index 0000000000..4965666b33 --- /dev/null +++ b/magnum/drivers/k8s_coreos_v1/version.py @@ -0,0 +1,17 @@ +# Copyright 2016 - Rackspace Hosting +# +# 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. + +version = '1.0.0' +driver = 'k8s_coreos' +container_version = '1.9.0' diff --git a/magnum/drivers/k8s_fedora_atomic_v1/template_def.py b/magnum/drivers/k8s_fedora_atomic_v1/template_def.py index 634a7af5a4..c538a5bc24 100644 --- a/magnum/drivers/k8s_fedora_atomic_v1/template_def.py +++ b/magnum/drivers/k8s_fedora_atomic_v1/template_def.py @@ -77,6 +77,8 @@ class K8sTemplateDefinition(template_def.BaseTemplateDefinition): param_type=str) self.add_parameter('insecure_registry_url', baymodel_attr='insecure_registry') + self.add_parameter('kube_version', + bay_attr='coe_version') self.add_output('api_address', bay_attr='api_address', @@ -157,6 +159,10 @@ class AtomicK8sTemplateDefinition(K8sTemplateDefinition): else: return ['../../common/templates/environments/no_master_lb.yaml'] + @property + def driver_module_path(self): + return __name__[:__name__.rindex('.')] + @property def template_path(self): return os.path.join(os.path.dirname(os.path.realpath(__file__)), @@ -214,6 +220,10 @@ class FedoraK8sIronicTemplateDefinition(AtomicK8sTemplateDefinition): extra_params=extra_params, **kwargs) + @property + def driver_module_path(self): + return __name__[:__name__.rindex('.')] + @property def template_path(self): return os.path.join(os.path.dirname(os.path.realpath(__file__)), diff --git a/magnum/drivers/k8s_fedora_atomic_v1/version.py b/magnum/drivers/k8s_fedora_atomic_v1/version.py index e20bac7f60..7f1702c334 100644 --- a/magnum/drivers/k8s_fedora_atomic_v1/version.py +++ b/magnum/drivers/k8s_fedora_atomic_v1/version.py @@ -14,3 +14,4 @@ version = '1.0.0' driver = 'k8s_fedora_atomic' +container_version = '1.9.1' diff --git a/magnum/drivers/mesos_ubuntu_v1/template_def.py b/magnum/drivers/mesos_ubuntu_v1/template_def.py index d571cfd519..6a20736e31 100644 --- a/magnum/drivers/mesos_ubuntu_v1/template_def.py +++ b/magnum/drivers/mesos_ubuntu_v1/template_def.py @@ -87,6 +87,10 @@ class UbuntuMesosTemplateDefinition(template_def.BaseTemplateDefinition): else: return ['../../common/templates/environments/no_master_lb.yaml'] + @property + def driver_module_path(self): + return __name__[:__name__.rindex('.')] + @property def template_path(self): return os.path.join(os.path.dirname(os.path.realpath(__file__)), diff --git a/magnum/drivers/mesos_ubuntu_v1/version.py b/magnum/drivers/mesos_ubuntu_v1/version.py new file mode 100644 index 0000000000..e012d87314 --- /dev/null +++ b/magnum/drivers/mesos_ubuntu_v1/version.py @@ -0,0 +1,17 @@ +# Copyright 2016 - Rackspace Hosting +# +# 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. + +version = '1.0.0' +driver = 'mesos_ubuntu' +container_version = '1.9.1' diff --git a/magnum/drivers/swarm_fedora_atomic_v1/template_def.py b/magnum/drivers/swarm_fedora_atomic_v1/template_def.py index bea785d2f2..868aa70638 100644 --- a/magnum/drivers/swarm_fedora_atomic_v1/template_def.py +++ b/magnum/drivers/swarm_fedora_atomic_v1/template_def.py @@ -71,6 +71,9 @@ class AtomicSwarmTemplateDefinition(template_def.BaseTemplateDefinition): baymodel_attr='registry_enabled') self.add_parameter('docker_storage_driver', baymodel_attr='docker_storage_driver') + self.add_parameter('swarm_version', + bay_attr='coe_version') + self.add_output('api_address', bay_attr='api_address', mapping_type=SwarmApiAddressOutputMapping) @@ -116,6 +119,10 @@ class AtomicSwarmTemplateDefinition(template_def.BaseTemplateDefinition): else: return ['../../common/templates/environments/no_master_lb.yaml'] + @property + def driver_module_path(self): + return __name__[:__name__.rindex('.')] + @property def template_path(self): return os.path.join(os.path.dirname(os.path.realpath(__file__)), diff --git a/magnum/drivers/swarm_fedora_atomic_v1/version.py b/magnum/drivers/swarm_fedora_atomic_v1/version.py index 7889a173d6..a36bff97b8 100644 --- a/magnum/drivers/swarm_fedora_atomic_v1/version.py +++ b/magnum/drivers/swarm_fedora_atomic_v1/version.py @@ -14,3 +14,4 @@ version = '1.0.0' driver = 'swarm_atomic' +container_version = '1.9.1' diff --git a/magnum/objects/bay.py b/magnum/objects/bay.py index 74b86dff0b..800d2e4681 100644 --- a/magnum/objects/bay.py +++ b/magnum/objects/bay.py @@ -36,7 +36,8 @@ class Bay(base.MagnumPersistentObject, base.MagnumObject, # Add 'trustee_user_name', 'trustee_password', # 'trustee_user_id' field # Version 1.6: Add rollback support for Bay - VERSION = '1.6' + # Version 1.7: Added 'coe_version' and 'container_version' fields + VERSION = '1.7' dbapi = dbapi.get_instance() @@ -63,7 +64,9 @@ class Bay(base.MagnumPersistentObject, base.MagnumObject, 'trust_id': fields.StringField(nullable=True), 'trustee_username': fields.StringField(nullable=True), 'trustee_password': fields.StringField(nullable=True), - 'trustee_user_id': fields.StringField(nullable=True) + 'trustee_user_id': fields.StringField(nullable=True), + 'coe_version': fields.StringField(nullable=True), + 'container_version': fields.StringField(nullable=True) } @staticmethod diff --git a/magnum/tests/unit/conductor/handlers/test_bay_conductor.py b/magnum/tests/unit/conductor/handlers/test_bay_conductor.py index 279273faeb..03465e25d8 100644 --- a/magnum/tests/unit/conductor/handlers/test_bay_conductor.py +++ b/magnum/tests/unit/conductor/handlers/test_bay_conductor.py @@ -502,6 +502,7 @@ class TestHeatPoller(base.TestCase): baymodel = objects.BayModel(self.context, **baymodel_dict) mock_retrieve_baymodel.return_value = baymodel poller = bay_conductor.HeatPoller(mock_openstack_client, bay) + poller.get_version_info = mock.MagicMock() return (mock_heat_stack, bay, poller) def test_poll_and_check_send_notification(self): diff --git a/magnum/tests/unit/conductor/handlers/test_k8s_bay_conductor.py b/magnum/tests/unit/conductor/handlers/test_k8s_bay_conductor.py index 34a80f288d..264cdef482 100644 --- a/magnum/tests/unit/conductor/handlers/test_k8s_bay_conductor.py +++ b/magnum/tests/unit/conductor/handlers/test_k8s_bay_conductor.py @@ -67,6 +67,7 @@ class TestBayConductorWithK8s(base.TestCase): 'trustee_password': 'fake_trustee_password', 'trustee_user_id': '7b489f04-b458-4541-8179-6a48a553e656', 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', + 'coe_version': 'fake-version', } self.context.auth_url = 'http://192.168.10.10:5000/v3' self.context.user_name = 'fake_user' @@ -172,6 +173,7 @@ class TestBayConductorWithK8s(base.TestCase): 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', 'auth_url': 'http://192.168.10.10:5000/v3', 'insecure_registry_url': '10.0.0.1:5000', + 'kube_version': 'fake-version', } if missing_attr is not None: expected.pop(mapping[missing_attr], None) @@ -242,6 +244,7 @@ class TestBayConductorWithK8s(base.TestCase): 'username': 'fake_user', 'volume_driver': 'volume_driver', 'insecure_registry_url': '10.0.0.1:5000', + 'kube_version': 'fake-version', } self.assertEqual(expected, definition) @@ -299,6 +302,7 @@ class TestBayConductorWithK8s(base.TestCase): 'bay_uuid': self.bay_dict['uuid'], 'magnum_url': self.mock_osc.magnum_url.return_value, 'insecure_registry_url': '10.0.0.1:5000', + 'kube_version': 'fake-version', } self.assertEqual(expected, definition) self.assertEqual( @@ -353,6 +357,7 @@ class TestBayConductorWithK8s(base.TestCase): 'bay_uuid': self.bay_dict['uuid'], 'magnum_url': self.mock_osc.magnum_url.return_value, 'insecure_registry_url': '10.0.0.1:5000', + 'kube_version': 'fake-version', } self.assertEqual(expected, definition) self.assertEqual( @@ -515,6 +520,7 @@ class TestBayConductorWithK8s(base.TestCase): 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', 'auth_url': 'http://192.168.10.10:5000/v3', 'insecure_registry_url': '10.0.0.1:5000', + 'kube_version': 'fake-version', } self.assertEqual(expected, definition) self.assertEqual( diff --git a/magnum/tests/unit/conductor/handlers/test_mesos_bay_conductor.py b/magnum/tests/unit/conductor/handlers/test_mesos_bay_conductor.py index b990470a16..914e39741c 100644 --- a/magnum/tests/unit/conductor/handlers/test_mesos_bay_conductor.py +++ b/magnum/tests/unit/conductor/handlers/test_mesos_bay_conductor.py @@ -284,6 +284,7 @@ class TestBayConductorWithMesos(base.TestCase): baymodel = objects.BayModel(self.context, **self.baymodel_dict) mock_retrieve_baymodel.return_value = baymodel poller = bay_conductor.HeatPoller(mock_openstack_client, bay) + poller.get_version_info = mock.MagicMock() return (mock_heat_stack, bay, poller) def test_poll_node_count(self): diff --git a/magnum/tests/unit/conductor/handlers/test_swarm_bay_conductor.py b/magnum/tests/unit/conductor/handlers/test_swarm_bay_conductor.py index 668e19ec1c..715a370e5c 100644 --- a/magnum/tests/unit/conductor/handlers/test_swarm_bay_conductor.py +++ b/magnum/tests/unit/conductor/handlers/test_swarm_bay_conductor.py @@ -63,7 +63,8 @@ class TestBayConductorWithSwarm(base.TestCase): 'trustee_username': 'fake_trustee', 'trustee_password': 'fake_trustee_password', 'trustee_user_id': '7b489f04-b458-4541-8179-6a48a553e656', - 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de' + 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', + 'coe_version': 'fake-version' } osc_patcher = mock.patch('magnum.common.clients.OpenStackClients') self.mock_osc_class = osc_patcher.start() @@ -124,7 +125,8 @@ class TestBayConductorWithSwarm(base.TestCase): 'trustee_password': 'fake_trustee_password', 'trustee_user_id': '7b489f04-b458-4541-8179-6a48a553e656', 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', - 'auth_url': 'http://192.168.10.10:5000/v3' + 'auth_url': 'http://192.168.10.10:5000/v3', + 'swarm_version': 'fake-version' } self.assertEqual(expected, definition) self.assertEqual( @@ -186,7 +188,8 @@ class TestBayConductorWithSwarm(base.TestCase): 'trustee_user_id': '7b489f04-b458-4541-8179-6a48a553e656', 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', 'auth_url': 'http://192.168.10.10:5000/v3', - 'docker_storage_driver': 'devicemapper' + 'docker_storage_driver': 'devicemapper', + 'swarm_version': 'fake-version' } self.assertEqual(expected, definition) self.assertEqual( @@ -240,7 +243,8 @@ class TestBayConductorWithSwarm(base.TestCase): 'trustee_password': 'fake_trustee_password', 'trustee_user_id': '7b489f04-b458-4541-8179-6a48a553e656', 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', - 'auth_url': 'http://192.168.10.10:5000/v3' + 'auth_url': 'http://192.168.10.10:5000/v3', + 'swarm_version': 'fake-version' } self.assertEqual(expected, definition) self.assertEqual( @@ -296,7 +300,8 @@ class TestBayConductorWithSwarm(base.TestCase): 'trustee_password': 'fake_trustee_password', 'trustee_user_id': '7b489f04-b458-4541-8179-6a48a553e656', 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', - 'auth_url': 'http://192.168.10.10:5000/v3' + 'auth_url': 'http://192.168.10.10:5000/v3', + 'swarm_version': 'fake-version' } self.assertEqual(expected, definition) self.assertEqual( @@ -353,7 +358,8 @@ class TestBayConductorWithSwarm(base.TestCase): 'trustee_password': 'fake_trustee_password', 'trustee_user_id': '7b489f04-b458-4541-8179-6a48a553e656', 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', - 'auth_url': 'http://192.168.10.10:5000/v3' + 'auth_url': 'http://192.168.10.10:5000/v3', + 'swarm_version': 'fake-version' } self.assertEqual(expected, definition) self.assertEqual( @@ -374,6 +380,7 @@ class TestBayConductorWithSwarm(base.TestCase): baymodel = objects.BayModel(self.context, **self.baymodel_dict) mock_retrieve_baymodel.return_value = baymodel poller = bay_conductor.HeatPoller(mock_openstack_client, bay) + poller.get_version_info = mock.MagicMock() return (mock_heat_stack, bay, poller) def test_poll_node_count(self): diff --git a/magnum/tests/unit/objects/test_bay.py b/magnum/tests/unit/objects/test_bay.py index d4efd90a3d..b18bc2768a 100644 --- a/magnum/tests/unit/objects/test_bay.py +++ b/magnum/tests/unit/objects/test_bay.py @@ -32,6 +32,8 @@ class TestBayObject(base.DbTestCase): self.fake_bay['trustee_username'] = 'trustee_user' self.fake_bay['trustee_user_id'] = 'trustee_user_id' self.fake_bay['trustee_password'] = 'password' + self.fake_bay['coe_version'] = 'fake-coe-version' + self.fake_bay['container_version'] = 'fake-container-version' baymodel_id = self.fake_bay['baymodel_id'] self.fake_baymodel = objects.BayModel(uuid=baymodel_id) diff --git a/magnum/tests/unit/objects/test_objects.py b/magnum/tests/unit/objects/test_objects.py index 01b7fdc71e..226cd0af7b 100644 --- a/magnum/tests/unit/objects/test_objects.py +++ b/magnum/tests/unit/objects/test_objects.py @@ -362,7 +362,7 @@ class TestObject(test_base.TestCase, _TestObject): # For more information on object version testing, read # http://docs.openstack.org/developer/magnum/objects.html object_data = { - 'Bay': '1.6-2386f79585a6c24bc7960884a4d0ebce', + 'Bay': '1.7-88cb12f991721fe31602dc3fd7acd654', 'BayModel': '1.15-9b961246b348aa380783dae14014e423', 'Certificate': '1.0-2aff667971b85c1edf8d15684fd7d5e2', 'MyObj': '1.0-b43567e512438205e32f4e95ca616697',