From abf6e91f55d92ee93c8229246f518cccb12d1324 Mon Sep 17 00:00:00 2001 From: mukultaneja Date: Wed, 24 Jun 2020 14:13:24 -0400 Subject: [PATCH] Removing multiple options to instantiate Image class This commit does following, 1. Modifies the Image class to be instantiated with a generic repotag property 2. Removes the ImageID property 3. Modifies the tests appropriately Resolved: #747 Signed-off-by: mukultaneja --- tern/classes/docker_image.py | 72 +++++++++++--------------------- tern/classes/image.py | 12 +++--- tests/test_class_docker_image.py | 7 ---- tests/test_class_image.py | 8 ++-- tests/test_class_template.py | 2 +- tests/test_fixtures.py | 4 +- 6 files changed, 37 insertions(+), 68 deletions(-) diff --git a/tern/classes/docker_image.py b/tern/classes/docker_image.py index 6a077115..e562ddd8 100644 --- a/tern/classes/docker_image.py +++ b/tern/classes/docker_image.py @@ -24,35 +24,31 @@ class DockerImage(Image): history: a list of commands used to create the filesystem layers to_dict: return a dict representation of the object ''' - def __init__(self, repotag=None, image_id=None): - '''Initialize using repotag and image_id''' - super().__init__(image_id) - self.__repotag = repotag + def __init__(self, repotag=None): + '''Initialize using repotag''' + super().__init__(repotag) self.__repotags = [] self.__history = None - if self.repotag is not None: - # parse the repotag - repo_dict = general.parse_image_string(self.__repotag) - self._name = repo_dict.get('name') - self._tag = repo_dict.get('tag') - self.set_checksum( - repo_dict.get('digest_type'), repo_dict.get('digest')) - if not self.checksum and general.check_tar(repotag) is False: - # if there is no checksum, get the digest type - docker_image = container.check_image(self.__repotag) - # this object could be representing an image built from - # a Dockerfile, so it may not have a digest - # so check for that condition - if docker_image.attrs['RepoDigests']: - image_name_digest = container.get_image_digest( - docker_image) - repo_dict = general.parse_image_string(image_name_digest) - self.set_checksum( - repo_dict.get('digest_type'), repo_dict.get('digest')) - - @property - def repotag(self): - return self.__repotag + if self.repotag is None: + raise NameError("Image object initialized with no repotag") + + # parse the repotag + repo_dict = general.parse_image_string(self._repotag) + self._name = repo_dict.get('name') + self._tag = repo_dict.get('tag') + self.set_checksum( + repo_dict.get('digest_type'), repo_dict.get('digest')) + if not self.checksum and general.check_tar(repotag) is False: + # if there is no checksum, get the digest type + docker_image = container.check_image(self._repotag) + # this object could be representing an image built from + # a Dockerfile, so it may not have a digest + # so check for that condition + if docker_image.attrs['RepoDigests']: + image_name_digest = container.get_image_digest(docker_image) + repo_dict = general.parse_image_string(image_name_digest) + self.set_checksum( + repo_dict.get('digest_type'), repo_dict.get('digest')) @property def repotags(self): @@ -68,18 +64,6 @@ def to_dict(self, template=None): di_dict = super().to_dict(template) return di_dict - def get_image_option(self): - '''Check to see which value was used to init the image object - Return the value that was used. If neither one was used raise - NameError. If both were used return the id''' - if self.repotag is not None and self.image_id is not None: - return self.image_id - if self.repotag is not None: - return self.repotag - if self.image_id is not None: - return self.image_id - raise NameError("Image object initialized with no repotag or ID") - def get_image_manifest(self): '''Assuming that there is a temp folder with a manifest.json of an image inside, get a dict of the manifest.json file''' @@ -100,12 +84,6 @@ def get_image_config_file(self, manifest): '''Given the manifest, return the config file''' return manifest[0].get('Config') - def get_image_id(self, manifest): - '''Given the manifest, return the image id - This happens to be the config file's sha256sum''' - config_file = self.get_image_config_file(manifest) - return config_file.split('.')[0] - def get_image_repotags(self, manifest): '''Given the manifest, return the list of image tag strings''' return manifest[0].get('RepoTags') @@ -163,10 +141,8 @@ def set_layer_created_by(self): def load_image(self): '''Load image metadata using docker commands''' try: - option = self.get_image_option() - container.extract_image_metadata(option) + container.extract_image_metadata(self.repotag) self._manifest = self.get_image_manifest() - self._image_id = self.get_image_id(self._manifest) self.__repotags = self.get_image_repotags(self._manifest) self._config = self.get_image_config(self._manifest) self.__history = self.get_image_history(self._config) diff --git a/tern/classes/image.py b/tern/classes/image.py index 126dacc0..775262ad 100644 --- a/tern/classes/image.py +++ b/tern/classes/image.py @@ -26,9 +26,9 @@ class Image: add_checksums: add new checksums in the existing list of the checksums to_dict: return a python dictionary representation of the image ''' - def __init__(self, image_id=None): - '''Either initialize using id''' - self._image_id = image_id + def __init__(self, repotag=None): + '''Initialize using the image's repo name and tag string''' + self._repotag = repotag self._name = '' self._tag = '' self._manifest = {} @@ -44,8 +44,8 @@ def manifest(self): return self._manifest @property - def image_id(self): - return self._image_id + def repotag(self): + return self._repotag @property def config(self): @@ -170,7 +170,7 @@ def get_human_readable_id(self): '''Some reports like SPDX want a unique name for the full image and this is currently not supported by any image tool. So using a combination of image id, name and tag instead''' - name = self.image_id[:10] + name = self.repotag[:10] if self.name: name = name + '-{}'.format(self.name) if self.tag: diff --git a/tests/test_class_docker_image.py b/tests/test_class_docker_image.py index 1e555cde..6058fbef 100644 --- a/tests/test_class_docker_image.py +++ b/tests/test_class_docker_image.py @@ -34,8 +34,6 @@ def setUp(self): 'a9a20752aa1ad7582c667704fda9f00' '4cc4bfd8601fac7f2656c7567bb4') # constants for this image - self.image_id = ('acb194ad84d0f9734e794fbbdbb65fb' - '7db6eda83f33e9e817bcc75b1bdd99f5e') self.layer = ('c1c3a87012e7ff5791b31e94515b661' 'cdf06f6d5dc2f9a6245eda8774d257a13') self.no_layers = 1 @@ -76,7 +74,6 @@ def testInstance(self): self.assertTrue(self.image.checksum, '20b32a9a20752aa1ad7582c66' '7704fda9f004cc4bfd8601fac7' 'f2656c7567bb4') - self.assertFalse(self.image.image_id) self.assertFalse(self.image.manifest) self.assertFalse(self.image.repotags) self.assertFalse(self.image.config) @@ -98,16 +95,12 @@ def testInstance(self): def testLoadImage(self): self.image.load_image() - self.assertEqual(self.image.image_id, self.image_id) self.assertEqual(self.image.layers[0].diff_id, self.layer) self.assertEqual(len(self.image.layers), self.no_layers) self.assertEqual(self.image.layers[0].created_by, self.created_by) self.assertEqual(self.image.layers[0].checksum_type, 'sha256') self.assertEqual(self.image.layers[0].checksum, self.layer) - def testGetImageOption(self): - self.assertEqual(self.image.get_image_option(), self.image.repotag) - def testGetLayerDiffIds(self): self.image.load_image() self.assertEqual(len(self.image.get_layer_diff_ids()), self.no_layers) diff --git a/tests/test_class_image.py b/tests/test_class_image.py index 536f98a1..30c00dbd 100644 --- a/tests/test_class_image.py +++ b/tests/test_class_image.py @@ -26,7 +26,7 @@ def tearDown(self): del self.image3 def testInstance(self): - self.assertEqual(self.image1.image_id, '1234abcd') + self.assertEqual(self.image1.repotag, '1234abcd') self.assertFalse(self.image1.name) self.assertFalse(self.image1.manifest) self.assertFalse(self.image1.tag) @@ -35,7 +35,7 @@ def testInstance(self): self.assertIsInstance(self.image1.origins, Origins) def testLoadImage(self): - self.assertEqual(self.image2.image_id, '5678efgh') + self.assertEqual(self.image2.repotag, '5678efgh') self.assertFalse(self.image2.layers) self.assertFalse(self.image2.name) self.assertFalse(self.image2.tag) @@ -57,7 +57,7 @@ def testGetLayerObject(self): def testToDict(self): self.image2.load_image() a_dict = self.image2.to_dict() - self.assertEqual(a_dict['image_id'], '5678efgh') + self.assertEqual(a_dict['repotag'], '5678efgh') self.assertEqual(len(a_dict['layers']), 1) self.assertEqual(len(a_dict['layers'][0]['packages']), 2) @@ -68,7 +68,7 @@ def testToDictTemplate(self): dict1 = self.image2.to_dict(template1) dict2 = self.image2.to_dict(template2) self.assertEqual(len(dict1.keys()), 2) - self.assertEqual(dict1['image.id'], '5678efgh') + self.assertEqual(dict1['image.repotag'], '5678efgh') self.assertEqual(len(dict1['image.layers']), 1) self.assertEqual(len(dict2.keys()), 3) self.assertFalse(dict2['notes']) diff --git a/tests/test_class_template.py b/tests/test_class_template.py index 0624b1da..186bf6c9 100644 --- a/tests/test_class_template.py +++ b/tests/test_class_template.py @@ -35,7 +35,7 @@ def testImageLayer(self): def testImage(self): mapping = self.template1.image() - self.assertEqual(mapping['image_id'], 'image.id') + self.assertEqual(mapping['repotag'], 'image.repotag') self.assertEqual(mapping['layers'], 'image.layers') def testNotice(self): diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index 5c48bdda..5b3e25b6 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -46,7 +46,7 @@ def image_layer(self): 'files': 'layer.files'} def image(self): - return {'image_id': 'image.id', + return {'repotag': 'image.repotag', 'layers': 'image.layers'} @@ -80,7 +80,7 @@ def image_layer(self): return mapping def image(self): - mapping = {'image_id': 'image.id', + mapping = {'repotag': 'image.repotag', 'layers': 'image.layers'} # we update the mapping with another defined mapping mapping.update(self.origins())