diff --git a/CHANGES/1767.feature b/CHANGES/1767.feature index 2dc1a29af..ead8ebcc2 100644 --- a/CHANGES/1767.feature +++ b/CHANGES/1767.feature @@ -1,2 +1,4 @@ -The Manifest model has been enhanced with a new `architecture` field, -which specifies the CPU architecture for which the binaries in the image are designed to run. +The Manifest model has been enhanced with a new: + * `architecture` field, which specifies the CPU architecture for which the binaries in the + image are designed to run. + * `os` field, which specifies the operating system which the image is built to run on. diff --git a/pulp_container/app/management/commands/container-repair-manifest-metadatas.py b/pulp_container/app/management/commands/container-repair-manifest-metadatas.py index 4d873419a..5c5173ed2 100644 --- a/pulp_container/app/management/commands/container-repair-manifest-metadatas.py +++ b/pulp_container/app/management/commands/container-repair-manifest-metadatas.py @@ -16,7 +16,7 @@ class Command(BaseCommand): """ - A management command to handle the initialization of empty architecture fields for + A management command to handle the initialization of empty architecture and os fields for container images. This command retrieves a list of manifests that have a null architecture field and @@ -54,7 +54,7 @@ def update_manifests(self, manifests_qs): manifests_to_update.append(manifest) if len(manifests_to_update) > 1000: - fields_to_update = ["architecture"] + fields_to_update = ["architecture", "os"] manifests_qs.model.objects.bulk_update( manifests_to_update, fields_to_update, @@ -63,7 +63,7 @@ def update_manifests(self, manifests_qs): manifests_to_update.clear() if manifests_to_update: - fields_to_update = ["architecture"] + fields_to_update = ["architecture", "os"] manifests_qs.model.objects.bulk_update( manifests_to_update, fields_to_update, diff --git a/pulp_container/app/migrations/0043_add_manifest_os.py b/pulp_container/app/migrations/0043_add_manifest_os.py new file mode 100644 index 000000000..2631ce0a9 --- /dev/null +++ b/pulp_container/app/migrations/0043_add_manifest_os.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.16 on 2024-09-24 11:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('container', '0042_add_manifest_architecture'), + ] + + operations = [ + migrations.AddField( + model_name='manifest', + name='os', + field=models.TextField(null=True), + ), + ] diff --git a/pulp_container/app/models.py b/pulp_container/app/models.py index d85a13e09..ee0457cb9 100644 --- a/pulp_container/app/models.py +++ b/pulp_container/app/models.py @@ -79,6 +79,7 @@ class Manifest(Content): is_flatpak (models.BooleanField): Indicates whether the image is a flatpak package or not. architecture (models.TextField): CPU architecture for which the binaries in the image are designed to run. + os (models.TextField): Operating System which the image is built to run on. Relations: blobs (models.ManyToManyField): Many-to-many relationship with Blob. @@ -106,6 +107,7 @@ class Manifest(Content): annotations = models.JSONField(default=dict) labels = models.JSONField(default=dict) architecture = models.TextField(null=True) + os = models.TextField(null=True) is_bootable = models.BooleanField(default=False) is_flatpak = models.BooleanField(default=False) @@ -127,7 +129,7 @@ def init_metadata(self, manifest_data=None): has_annotations = self.init_annotations(manifest_data) has_labels = self.init_labels() has_image_nature = self.init_image_nature() - self.init_architecture(manifest_data) + self.init_architecture_and_os(manifest_data) return has_annotations or has_labels or has_image_nature def init_annotations(self, manifest_data=None): @@ -180,7 +182,7 @@ def init_manifest_nature(self): else: return False - def init_architecture(self, manifest_data): + def init_architecture_and_os(self, manifest_data): # manifestv2 schema1 has the architecture definition in the Manifest (not in the ConfigBlob) if architecture := manifest_data.get("architecture", None): self.architecture = architecture @@ -191,6 +193,7 @@ def init_architecture(self, manifest_data): blob_artifact = Artifact.objects.get(sha256=config_blob_sha256.removeprefix("sha256:")) config_blob, _ = get_content_data(blob_artifact) self.architecture = config_blob.get("architecture", None) + self.os = config_blob.get("os", None) def is_bootable_image(self): if ( diff --git a/pulp_container/app/registry.py b/pulp_container/app/registry.py index be1d3f9cf..3c287e389 100644 --- a/pulp_container/app/registry.py +++ b/pulp_container/app/registry.py @@ -455,11 +455,11 @@ async def init_pending_content(self, digest, manifest_data, media_type, raw_text data=raw_text_data, ) - # if media_type of schema1 configure only manifest architecture + # if media_type of schema1 configure only manifest architecture and os if media_type in (MEDIA_TYPE.MANIFEST_V2, MEDIA_TYPE.MANIFEST_OCI): await sync_to_async(manifest.init_metadata)(manifest_data=manifest_data) else: - await sync_to_async(manifest.init_architecture)(manifest_data=manifest_data) + await sync_to_async(manifest.init_architecture_and_os)(manifest_data=manifest_data) try: await manifest.asave() diff --git a/pulp_container/app/serializers.py b/pulp_container/app/serializers.py index d8e121d62..e07bb9be7 100644 --- a/pulp_container/app/serializers.py +++ b/pulp_container/app/serializers.py @@ -108,6 +108,11 @@ class ManifestSerializer(NoArtifactContentSerializer): required=False, default=None, ) + os = serializers.CharField( + help_text="The name of the operating system which the image is built to run on.", + required=False, + default=None, + ) class Meta: fields = NoArtifactContentSerializer.Meta.fields + ( @@ -122,6 +127,7 @@ class Meta: "is_bootable", "is_flatpak", "architecture", + "os", ) model = models.Manifest diff --git a/pulp_container/app/tasks/builder.py b/pulp_container/app/tasks/builder.py index 8cbcf4242..cee800c57 100644 --- a/pulp_container/app/tasks/builder.py +++ b/pulp_container/app/tasks/builder.py @@ -86,6 +86,7 @@ def add_image_from_directory_to_repository(path, repository, tag): blob_artifact = Artifact.objects.get(sha256=config_blob.digest.removeprefix("sha256:")) config_blob_dict, _ = get_content_data(blob_artifact) manifest.architecture = config_blob_dict.get("architecture", None) + manifest.os = config_blob_dict.get("os", None) manifest.save() pks_to_add = [] diff --git a/pulp_container/app/tasks/sync_stages.py b/pulp_container/app/tasks/sync_stages.py index 3aec62f5c..f59cb0cef 100644 --- a/pulp_container/app/tasks/sync_stages.py +++ b/pulp_container/app/tasks/sync_stages.py @@ -647,6 +647,7 @@ def _post_save(self, batch): ) config_blob, _ = get_content_data(blob_artifact) manifest_dc.architecture = config_blob.get("architecture", None) + manifest_dc.os = config_blob.get("os", None) manifest_dc.save() if blob_manifests: diff --git a/pulp_container/tests/functional/api/test_build_images.py b/pulp_container/tests/functional/api/test_build_images.py index bdbe8d800..2b281377c 100644 --- a/pulp_container/tests/functional/api/test_build_images.py +++ b/pulp_container/tests/functional/api/test_build_images.py @@ -66,3 +66,4 @@ def test_build_image( manifest = container_manifest_api.list(digest=image[0]["Digest"]) manifest = manifest.to_dict()["results"][0] assert manifest["architecture"] == "amd64" + assert manifest["os"] == "linux" diff --git a/pulp_container/tests/functional/api/test_pull_through_cache.py b/pulp_container/tests/functional/api/test_pull_through_cache.py index 14387a3c4..73dccceea 100644 --- a/pulp_container/tests/functional/api/test_pull_through_cache.py +++ b/pulp_container/tests/functional/api/test_pull_through_cache.py @@ -64,6 +64,7 @@ def _pull_and_verify(images, pull_through_distribution): manifest = container_manifest_api.list(digest=local_image[0]["Digest"]) manifest = manifest.to_dict()["results"][0] assert manifest["architecture"] == "amd64" + assert manifest["os"] == "linux" path, tag = local_image_path.split(":") tags_to_verify.append(tag) diff --git a/pulp_container/tests/functional/api/test_push_content.py b/pulp_container/tests/functional/api/test_push_content.py index cee937d0b..d2a26db52 100644 --- a/pulp_container/tests/functional/api/test_push_content.py +++ b/pulp_container/tests/functional/api/test_push_content.py @@ -55,6 +55,7 @@ def test_push_using_registry_client_admin( manifest = container_manifest_api.list(digest=local_image[0]["Digest"]) manifest = manifest.to_dict()["results"][0] assert manifest["architecture"] == "amd64" + assert manifest["os"] == "linux" # ensure that same content can be pushed twice without permission errors local_registry.tag_and_push(image_path, local_url) diff --git a/pulp_container/tests/functional/api/test_sync.py b/pulp_container/tests/functional/api/test_sync.py index aa812f780..761d0a83b 100644 --- a/pulp_container/tests/functional/api/test_sync.py +++ b/pulp_container/tests/functional/api/test_sync.py @@ -71,6 +71,7 @@ def test_basic_sync( ) manifest = manifest.to_dict()["results"][0] assert manifest["architecture"] == "amd64" + assert manifest["os"] == "linux" @pytest.mark.parallel