Merge "Add BuildRequestList object"

This commit is contained in:
Jenkins
2016-08-26 17:17:00 +00:00
committed by Gerrit Code Review
4 changed files with 628 additions and 0 deletions
+182
View File
@@ -10,6 +10,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import functools
import re
from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
@@ -191,3 +194,182 @@ class BuildRequest(base.NovaObject):
@base.remotable
def destroy(self):
self._destroy_in_db(self._context, self.instance_uuid)
@base.NovaObjectRegistry.register
class BuildRequestList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'objects': fields.ListOfObjectsField('BuildRequest'),
}
@staticmethod
@db.api_context_manager.reader
def _get_all_from_db(context):
query = context.session.query(api_models.BuildRequest)
if not context.is_admin:
query = query.filter_by(project_id=context.project_id)
db_reqs = query.all()
return db_reqs
@base.remotable_classmethod
def get_all(cls, context):
db_build_reqs = cls._get_all_from_db(context)
return base.obj_make_list(context, cls(context), objects.BuildRequest,
db_build_reqs)
@staticmethod
def _pass_exact_filters(instance, filters):
for filter_key, filter_val in filters.items():
if filter_key in ('metadata', 'system_metadata'):
if isinstance(filter_val, list):
for item in filter_val:
for k, v in item.items():
if (k not in instance.metadata or
v != instance.metadata[k]):
return False
else:
for k, v in filter_val.items():
if (k not in instance.metadata or
v != instance.metadata[k]):
return False
elif isinstance(filter_val, (list, tuple, set, frozenset)):
if not filter_val:
# Special value to indicate that nothing will match.
return None
if instance.get(filter_key, None) not in filter_val:
return False
else:
if instance.get(filter_key, None) != filter_val:
return False
return True
@staticmethod
def _pass_regex_filters(instance, filters):
for filter_name, filter_val in filters.items():
try:
instance_attr = getattr(instance, filter_name)
except AttributeError:
continue
# Sometimes the REGEX filter value is not a string
if not isinstance(filter_val, six.string_types):
filter_val = str(filter_val)
filter_re = re.compile(filter_val)
if instance_attr and not filter_re.search(str(instance_attr)):
return False
return True
@staticmethod
def _sort_build_requests(build_req_list, sort_keys, sort_dirs):
# build_req_list is a [] of build_reqs
sort_keys.reverse()
sort_dirs.reverse()
def sort_attr(sort_key, build_req):
if sort_key == 'id':
# 'id' is not set on the instance yet. Use the BuildRequest
# 'id' instead.
return build_req.id
return getattr(build_req.instance, sort_key)
for sort_key, sort_dir in zip(sort_keys, sort_dirs):
reverse = False if sort_dir.lower().startswith('asc') else True
build_req_list.sort(key=functools.partial(sort_attr, sort_key),
reverse=reverse)
return build_req_list
@base.remotable_classmethod
def get_by_filters(cls, context, filters, limit=None, marker=None,
sort_keys=None, sort_dirs=None):
if limit == 0:
return cls(context, objects=[])
# 'deleted' records can not be returned from here since build_requests
# are not soft deleted.
if filters.get('deleted', False):
return cls(context, objects=[])
# 'cleaned' records won't exist as they would need to be deleted.
if filters.get('cleaned', False):
return cls(context, objects=[])
# Because the build_requests table stores an instance as a serialized
# versioned object it is not feasible to do the filtering and sorting
# in the database. Just get all potentially relevant records and
# process them here. It should be noted that build requests are short
# lived so there should not be a lot of results to deal with.
build_requests = cls.get_all(context)
# Fortunately some filters do not apply here.
# 'tags' can not be applied at boot time so will not be set for an
# instance here.
# 'changes-since' works off of the updated_at field which has not yet
# been set at the point in the boot process where build_request still
# exists. So it can be ignored.
# 'deleted' and 'cleaned' are handled above.
sort_keys, sort_dirs = db.process_sort_params(sort_keys, sort_dirs,
default_dir='desc')
# For other filters that don't match this, we will do regexp matching
# Taken from db/sqlalchemy/api.py
exact_match_filter_names = ['project_id', 'user_id', 'image_ref',
'vm_state', 'instance_type_id', 'uuid',
'metadata', 'host', 'task_state',
'system_metadata']
exact_filters = {}
regex_filters = {}
for key, value in filters.items():
if key in exact_match_filter_names:
exact_filters[key] = value
else:
regex_filters[key] = value
# As much as possible this copies the logic from db/sqlalchemy/api.py
# instance_get_all_by_filters_sort. The main difference is that method
# builds a sql query and this filters in python.
filtered_build_reqs = []
for build_req in build_requests:
instance = build_req.instance
filter_result = cls._pass_exact_filters(instance, exact_filters)
if filter_result is None:
# The filter condition is such that nothing will match.
# Bail early.
return cls(context, objects=[])
if filter_result is False:
continue
if not cls._pass_regex_filters(instance, regex_filters):
continue
filtered_build_reqs.append(build_req)
if (len(filtered_build_reqs) < 2) or (not sort_keys):
# No need to sort
return cls(context, objects=filtered_build_reqs)
sorted_build_reqs = cls._sort_build_requests(filtered_build_reqs,
sort_keys, sort_dirs)
marker_index = 0
if marker:
for i, build_req in enumerate(sorted_build_reqs):
if build_req.instance.uuid == marker:
marker_index = i
break
len_build_reqs = len(sorted_build_reqs)
limit_index = len_build_reqs
if limit:
limit_index = marker_index + limit
if limit_index > len_build_reqs:
limit_index = len_build_reqs
return cls(context,
objects=sorted_build_reqs[marker_index:limit_index])
@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_serialization import jsonutils
from oslo_utils import uuidutils
from nova import context
@@ -19,6 +20,7 @@ from nova.objects import build_request
from nova import test
from nova.tests import fixtures
from nova.tests.unit import fake_build_request
from nova.tests.unit import fake_instance
class BuildRequestTestCase(test.NoDBTestCase):
@@ -82,3 +84,419 @@ class BuildRequestTestCase(test.NoDBTestCase):
self.instance_uuid)
db_req.destroy()
self.assertRaises(exception.BuildRequestNotFound, db_req.destroy)
class BuildRequestListTestCase(test.NoDBTestCase):
USES_DB_SELF = True
def setUp(self):
super(BuildRequestListTestCase, self).setUp()
# NOTE: This means that we're using a database for this test suite
# despite inheriting from NoDBTestCase
self.useFixture(fixtures.Database(database='api'))
self.project_id = 'fake-project'
self.context = context.RequestContext('fake-user', self.project_id)
def _create_req(self, project_id=None, instance=None):
kwargs = {}
if instance:
kwargs['instance'] = jsonutils.dumps(instance.obj_to_primitive())
args = fake_build_request.fake_db_req(**kwargs)
args.pop('id', None)
args['instance_uuid'] = uuidutils.generate_uuid()
args['project_id'] = self.project_id if not project_id else project_id
return build_request.BuildRequest._from_db_object(self.context,
build_request.BuildRequest(),
build_request.BuildRequest._create_in_db(self.context, args))
def test_get_all_empty(self):
req_objs = build_request.BuildRequestList.get_all(self.context)
self.assertEqual([], req_objs.objects)
def test_get_all(self):
reqs = [self._create_req(), self._create_req()]
req_list = build_request.BuildRequestList.get_all(self.context)
self.assertEqual(2, len(req_list))
for i in range(len(req_list)):
self.assertEqual(reqs[i].instance_uuid, req_list[i].instance_uuid)
objects.base.obj_equal_prims(reqs[i].instance,
req_list[i].instance)
def test_get_all_filter_by_project_id(self):
reqs = [self._create_req(), self._create_req(project_id='filter')]
req_list = build_request.BuildRequestList.get_all(self.context)
self.assertEqual(1, len(req_list))
self.assertEqual(reqs[0].project_id, req_list[0].project_id)
self.assertEqual(reqs[0].instance_uuid, req_list[0].instance_uuid)
objects.base.obj_equal_prims(reqs[0].instance,
req_list[0].instance)
def test_get_all_bypass_project_id_filter_as_admin(self):
reqs = [self._create_req(), self._create_req(project_id='filter')]
req_list = build_request.BuildRequestList.get_all(
self.context.elevated())
self.assertEqual(2, len(req_list))
for i in range(len(req_list)):
self.assertEqual(reqs[i].project_id, req_list[i].project_id)
self.assertEqual(reqs[i].instance_uuid, req_list[i].instance_uuid)
objects.base.obj_equal_prims(reqs[i].instance,
req_list[i].instance)
def test_get_by_filters(self):
reqs = [self._create_req(), self._create_req()]
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {}, sort_keys=['id'], sort_dirs=['asc'])
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(2, len(req_list))
for i in range(len(req_list)):
self.assertEqual(reqs[i].instance_uuid, req_list[i].instance_uuid)
objects.base.obj_equal_prims(reqs[i].instance,
req_list[i].instance)
def test_get_by_filters_limit_0(self):
self._create_req()
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {}, limit=0)
self.assertEqual([], req_list.objects)
def test_get_by_filters_deleted(self):
self._create_req()
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {'deleted': True})
self.assertEqual([], req_list.objects)
def test_get_by_filters_cleaned(self):
self._create_req()
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {'cleaned': True})
self.assertEqual([], req_list.objects)
def test_get_by_filters_exact_match(self):
instance_find = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, image_ref='findme')
instance_filter = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, image_ref='filterme')
reqs = [self._create_req(instance=instance_filter),
self._create_req(instance=instance_find)]
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {'image_ref': 'findme'})
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(1, len(req_list))
self.assertEqual(reqs[1].instance_uuid, req_list[0].instance_uuid)
objects.base.obj_equal_prims(reqs[1].instance,
req_list[0].instance)
def test_get_by_filters_exact_match_list(self):
instance_find = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, image_ref='findme')
instance_filter = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, image_ref='filterme')
reqs = [self._create_req(instance=instance_filter),
self._create_req(instance=instance_find)]
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {'image_ref': ['findme', 'fake']})
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(1, len(req_list))
self.assertEqual(reqs[1].instance_uuid, req_list[0].instance_uuid)
objects.base.obj_equal_prims(reqs[1].instance,
req_list[0].instance)
def test_get_by_filters_exact_match_metadata(self):
instance_find = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, metadata={'foo': 'bar'}, expected_attrs='metadata')
instance_filter = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, metadata={'bar': 'baz'}, expected_attrs='metadata')
reqs = [self._create_req(instance=instance_filter),
self._create_req(instance=instance_find)]
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {'metadata': {'foo': 'bar'}})
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(1, len(req_list))
self.assertEqual(reqs[1].instance_uuid, req_list[0].instance_uuid)
objects.base.obj_equal_prims(reqs[1].instance,
req_list[0].instance)
def test_get_by_filters_exact_match_metadata_list(self):
instance_find = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, metadata={'foo': 'bar', 'cat': 'meow'},
expected_attrs='metadata')
instance_filter = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, metadata={'bar': 'baz', 'cat': 'meow'},
expected_attrs='metadata')
reqs = [self._create_req(instance=instance_filter),
self._create_req(instance=instance_find)]
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {'metadata': [{'foo': 'bar'}, {'cat': 'meow'}]})
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(1, len(req_list))
self.assertEqual(reqs[1].instance_uuid, req_list[0].instance_uuid)
objects.base.obj_equal_prims(reqs[1].instance,
req_list[0].instance)
def test_get_by_filters_regex_match_one(self):
instance_find = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, display_name='find this one')
instance_filter = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, display_name='filter this one')
reqs = [self._create_req(instance=instance_filter),
self._create_req(instance=instance_find)]
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {'display_name': 'find'})
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(1, len(req_list))
self.assertEqual(reqs[1].instance_uuid, req_list[0].instance_uuid)
objects.base.obj_equal_prims(reqs[1].instance,
req_list[0].instance)
def test_get_by_filters_regex_match_both(self):
instance_find = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, display_name='find this one')
instance_filter = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, display_name='filter this one')
reqs = [self._create_req(instance=instance_filter),
self._create_req(instance=instance_find)]
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {'display_name': 'this'}, sort_keys=['id'],
sort_dirs=['asc'])
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(2, len(req_list))
for i in range(len(req_list)):
self.assertEqual(reqs[i].instance_uuid, req_list[i].instance_uuid)
objects.base.obj_equal_prims(reqs[i].instance,
req_list[i].instance)
def test_get_by_filters_sort_asc(self):
instance_1024 = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, root_gb=1024)
instance_512 = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, root_gb=512)
req_second = self._create_req(instance=instance_1024)
req_first = self._create_req(instance=instance_512)
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {}, sort_keys=['root_gb'], sort_dirs=['asc'])
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(2, len(req_list))
self.assertEqual(req_first.instance_uuid, req_list[0].instance_uuid)
objects.base.obj_equal_prims(req_first.instance, req_list[0].instance)
self.assertEqual(req_second.instance_uuid, req_list[1].instance_uuid)
objects.base.obj_equal_prims(req_second.instance, req_list[1].instance)
def test_get_by_filters_sort_desc(self):
instance_1024 = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, root_gb=1024)
instance_512 = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, root_gb=512)
req_second = self._create_req(instance=instance_512)
req_first = self._create_req(instance=instance_1024)
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {}, sort_keys=['root_gb'], sort_dirs=['desc'])
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(2, len(req_list))
self.assertEqual(req_first.instance_uuid, req_list[0].instance_uuid)
objects.base.obj_equal_prims(req_first.instance, req_list[0].instance)
self.assertEqual(req_second.instance_uuid, req_list[1].instance_uuid)
objects.base.obj_equal_prims(req_second.instance, req_list[1].instance)
def test_get_by_filters_sort_build_req_id(self):
# Create instance objects this way so that there is no 'id' set.
# The 'id' will not be populated on a BuildRequest.instance so this
# checks that sorting by 'id' uses the BuildRequest.id.
instance_1 = objects.Instance(self.context, host=None,
uuid=uuidutils.generate_uuid())
instance_2 = objects.Instance(self.context, host=None,
uuid=uuidutils.generate_uuid())
req_first = self._create_req(instance=instance_2)
req_second = self._create_req(instance=instance_1)
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {}, sort_keys=['id'], sort_dirs=['asc'])
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(2, len(req_list))
self.assertEqual(req_first.instance_uuid, req_list[0].instance_uuid)
objects.base.obj_equal_prims(req_first.instance, req_list[0].instance)
self.assertEqual(req_second.instance_uuid, req_list[1].instance_uuid)
objects.base.obj_equal_prims(req_second.instance, req_list[1].instance)
def test_get_by_filters_multiple_sort_keys(self):
instance_first = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, root_gb=512, image_ref='ccc')
instance_second = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, root_gb=512, image_ref='bbb')
instance_third = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, root_gb=1024, image_ref='aaa')
req_first = self._create_req(instance=instance_first)
req_third = self._create_req(instance=instance_third)
req_second = self._create_req(instance=instance_second)
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {}, sort_keys=['root_gb', 'image_ref'],
sort_dirs=['asc', 'desc'])
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(3, len(req_list))
self.assertEqual(req_first.instance_uuid, req_list[0].instance_uuid)
objects.base.obj_equal_prims(req_first.instance, req_list[0].instance)
self.assertEqual(req_second.instance_uuid, req_list[1].instance_uuid)
objects.base.obj_equal_prims(req_second.instance, req_list[1].instance)
self.assertEqual(req_third.instance_uuid, req_list[2].instance_uuid)
objects.base.obj_equal_prims(req_third.instance, req_list[2].instance)
def test_get_by_filters_marker(self):
instance = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None)
reqs = [self._create_req(),
self._create_req(instance=instance),
self._create_req()]
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {}, marker=instance.uuid, sort_keys=['id'],
sort_dirs=['asc'])
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(2, len(req_list))
for i, req in enumerate(reqs[1:]):
self.assertEqual(req.instance_uuid, req_list[i].instance_uuid)
objects.base.obj_equal_prims(req.instance,
req_list[i].instance)
def test_get_by_filters_limit(self):
reqs = [self._create_req(),
self._create_req(),
self._create_req()]
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {}, limit=2, sort_keys=['id'],
sort_dirs=['asc'])
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(2, len(req_list))
for i, req in enumerate(reqs[:2]):
self.assertEqual(req.instance_uuid, req_list[i].instance_uuid)
objects.base.obj_equal_prims(req.instance,
req_list[i].instance)
def test_get_by_filters_marker_limit(self):
instance = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None)
reqs = [self._create_req(),
self._create_req(instance=instance),
self._create_req(),
self._create_req()]
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {}, marker=instance.uuid, limit=2,
sort_keys=['id'], sort_dirs=['asc'])
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(2, len(req_list))
for i, req in enumerate(reqs[1:3]):
self.assertEqual(req.instance_uuid, req_list[i].instance_uuid)
objects.base.obj_equal_prims(req.instance,
req_list[i].instance)
def test_get_by_filters_marker_overlimit(self):
instance = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None)
reqs = [self._create_req(),
self._create_req(instance=instance),
self._create_req(),
self._create_req()]
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {}, marker=instance.uuid, limit=4,
sort_keys=['id'], sort_dirs=['asc'])
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(3, len(req_list))
for i, req in enumerate(reqs[1:]):
self.assertEqual(req.instance_uuid, req_list[i].instance_uuid)
objects.base.obj_equal_prims(req.instance,
req_list[i].instance)
def test_get_by_filters_bails_on_empty_list_check(self):
instance1 = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, image_ref='')
instance2 = fake_instance.fake_instance_obj(
self.context, objects.Instance, uuid=uuidutils.generate_uuid(),
host=None, image_ref='')
self._create_req(instance=instance1)
self._create_req(instance=instance2)
req_list = build_request.BuildRequestList.get_by_filters(
self.context, {'image_ref': []})
self.assertIsInstance(req_list, objects.BuildRequestList)
self.assertEqual(0, len(req_list))
@@ -125,3 +125,30 @@ class TestBuildRequestObject(test_objects._LocalTest,
class TestRemoteBuildRequestObject(test_objects._RemoteTest,
_TestBuildRequestObject):
pass
class _TestBuildRequestListObject(object):
@mock.patch.object(build_request.BuildRequestList, '_get_all_from_db')
def test_get_all(self, get_all):
fake_reqs = [fake_build_request.fake_db_req() for x in range(2)]
get_all.return_value = fake_reqs
req_objs = build_request.BuildRequestList.get_all(self.context)
self.assertEqual(2, len(req_objs))
for i in range(2):
self.assertEqual(fake_reqs[i]['instance_uuid'],
req_objs[i].instance_uuid)
self.assertEqual(fake_reqs[i]['project_id'],
req_objs[i].project_id)
self.assertIsInstance(req_objs[i].instance, objects.Instance)
class TestBuildRequestListObject(test_objects._LocalTest,
_TestBuildRequestListObject):
pass
class TestRemoteBuildRequestListObject(test_objects._RemoteTest,
_TestBuildRequestListObject):
pass
+1
View File
@@ -1106,6 +1106,7 @@ object_data = {
'BlockDeviceMapping': '1.17-5e094927f1251770dcada6ab05adfcdb',
'BlockDeviceMappingList': '1.17-1e568eecb91d06d4112db9fd656de235',
'BuildRequest': '1.1-5a5ce31c2f4dcd67088342a9164d13b4',
'BuildRequestList': '1.0-cd95608eccb89fbc702c8b52f38ec738',
'CellMapping': '1.0-7f1a7e85a22bbb7559fc730ab658b9bd',
'CellMappingList': '1.0-4ee0d9efdfd681fed822da88376e04d2',
'ComputeNode': '1.16-2436e5b836fa0306a3c4e6d9e5ddacec',