Include version info in bay/cluster show operation
Currently bay-show operation does not return bay/cluster version information. This change contain changes to return bay/cluster version and container version info. Change-Id: Ie12b6583e6d85faa3607f87295c04d72698034a5 Closes-Bug: #1613413
This commit is contained in:
parent
c1c6cf0214
commit
50bc376c4d
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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))
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__)),
|
||||
|
|
|
@ -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'
|
|
@ -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__)),
|
||||
|
|
|
@ -14,3 +14,4 @@
|
|||
|
||||
version = '1.0.0'
|
||||
driver = 'k8s_fedora_atomic'
|
||||
container_version = '1.9.1'
|
||||
|
|
|
@ -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__)),
|
||||
|
|
|
@ -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'
|
|
@ -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__)),
|
||||
|
|
|
@ -14,3 +14,4 @@
|
|||
|
||||
version = '1.0.0'
|
||||
driver = 'swarm_atomic'
|
||||
container_version = '1.9.1'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue