Git Product home page Git Product logo

pulp_container's Introduction

pulp_container's People

Contributors

ammaritiz avatar asmacdo avatar barnabycourt avatar beav avatar bmbouter avatar daviddavis avatar dependabot[bot] avatar dkliban avatar dralley avatar evgeni avatar fao89 avatar fdobrovolny avatar gerrod3 avatar git-hyagi avatar goosemania avatar ianballou avatar ipanova avatar jeremycline avatar jortel avatar lubosmj avatar mdellweg avatar mhrivnak avatar mibanescu avatar midnightercz avatar mikedep333 avatar pcreech avatar pulpbot avatar rochacbruno avatar seandst avatar werwty avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pulp_container's Issues

Feature request: whitelist upstreams

Author: joeydumont (joeydumont)

Redmine Issue: 5545, https://pulp.plan.io/issues/5545


I open this feature request after a short conversation on the mailing list: see the "pulp_docker: whitelist upstreams" thread.

I would like to be able to provide a list of whitelisted upstreams and create a single repository version with all of these upstreams. For example, I would like for users to be able to do:

docker pull my_docker_distribution/alpine/git
docker pull my_docker_distribution/postgresql

but not

docker pull my_docker_distribution/super_shady_container_image_hosted_on_Docker_Hub

where the underlying repositories would point to Docker Hub, or other container registries.

Thank you for any information!

As a user I can mount blobs across repositories

Author: @ipanova ([email protected])

Redmine Issue: 9241, https://pulp.plan.io/issues/9241


Given that the user, who is currently pushing an image, has READ access to another repository that already contains the blob, he should be able to mount blobs across repositories. The ability, that registry may provide is beneficial to save on network speed.

Cross blob mount works in the following way:
For every repository that container blob X will be asked a token with mount permission. If the user has no READ permission to any of those repos it will fall back and create the blob upload and upload the blob bits.

In these logs the are already existing repos busybox, busybox1, busybox2 that share same blob. Repo ina/busybox3 is being pushed and it has same blob that is contained in busybox, busybox1 and busybox2.
It tries to mount blob against each repo, fails and falls back to the regular blob upload.

.0.0.1 - - [16/Aug/2021:14:37:08 +0000] "PUT /v2/ina/busybox3/blobs/uploads/5e6887df-78f7-4908-ab7d-1e03a97754fd?digest=sha256%3Aa9efad4c351baa14138b2ddca283c33974c1957b59981f77642ccf4398981045 HTTP/1.1" 201

.0.0.1 - - [16/Aug/2021:14:37:07 +0000] "PATCH /v2/ina/busybox3/blobs/uploads/5e6887df-78f7-4908-ab7d-1e03a97754fd HTTP/1.1" 202 
.0.0.1 - - [16/Aug/2021:14:37:07 +0000] "POST /v2/ina/busybox3/blobs/uploads/ HTTP/1.1" 202 

.0.0.1 - - [16/Aug/2021:14:37:06 +0000] "POST /v2/ina/busybox3/blobs/uploads/?from=busybox&mount=sha256%3Aa9efad4c351baa14138b2ddca283c33974c1957b59981f77642ccf4398981045 HTTP/1.1" 401 
ngo.request:WARNING: Unauthorized: /v2/ina/busybox3/blobs/uploads/
 /pulp/container/busybox/blobs/sha256:a9efad4c351baa14138b2ddca283c33974c1957b59981f77642ccf4398981045?validate_token=bb5a4a4fffc5418d6b8d8f735e49caf38bb4660cf68a4a6fca3bc6e196550e60:fb629a583d896ba3e1a4888a83153a733a85e677771c2fe5a27342>
.0.0.1 - - [16/Aug/2021:14:37:06 +0000] "HEAD /v2/busybox/blobs/sha256:a9efad4c351baa14138b2ddca283c33974c1957b59981f77642ccf4398981045 HTTP/1.1" 302 
.0.0.1 - ina [16/Aug/2021:14:37:06 +0000] "GET /token/?account=ina&scope=repository%3Aina%2Fbusybox3%3Apull%2Cpush&scope=repository%3Abusybox%3Apull&service=localhost%3A24817 HTTP/1.0" 200 
.0.0.1 - - [16/Aug/2021:14:37:06 +0000] "POST /v2/ina/busybox3/blobs/uploads/?from=busybox1&mount=sha256%3Aa9efad4c351baa14138b2ddca283c33974c1957b59981f77642ccf4398981045 HTTP/1.1" 401 
ngo.request:WARNING: Unauthorized: /v2/ina/busybox3/blobs/uploads/
 /pulp/container/busybox1/blobs/sha256:a9efad4c351baa14138b2ddca283c33974c1957b59981f77642ccf4398981045?validate_token=d38d17fd475a24e228ed9d0418b937d7011954227d42945d9f5c14cca4afa50c:23939ede17923e540b63991e7372e1abed2223a26497c0581531b>
.0.0.1 - - [16/Aug/2021:14:37:06 +0000] "HEAD /v2/busybox1/blobs/sha256:a9efad4c351baa14138b2ddca283c33974c1957b59981f77642ccf4398981045 HTTP/1.1" 302 
.0.0.1 - ina [16/Aug/2021:14:37:06 +0000] "GET /token/?account=ina&scope=repository%3Aina%2Fbusybox3%3Apull%2Cpush&scope=repository%3Abusybox1%3Apull&service=localhost%3A24817 HTTP/1.0" 200 
.0.0.1 - - [16/Aug/2021:14:37:06 +0000] "POST /v2/ina/busybox3/blobs/uploads/?from=busybox2&mount=sha256%3Aa9efad4c351baa14138b2ddca283c33974c1957b59981f77642ccf4398981045 HTTP/1.1" 401 
ngo.request:WARNING: Unauthorized: /v2/ina/busybox3/blobs/uploads/
 /pulp/container/busybox2/blobs/sha256:a9efad4c351baa14138b2ddca283c33974c1957b59981f77642ccf4398981045?validate_token=4148bac928c3c8641bf5a40839c4e082334fc5242a787f99117eb956d4d99906:59026249fe55842485fbecd279c8b98e33df47c168ecf02cd6df4>
.0.0.1 - - [16/Aug/2021:14:37:05 +0000] "HEAD /v2/busybox2/blobs/sha256:a9efad4c351baa14138b2ddca283c33974c1957b59981f77642ccf4398981045 HTTP/1.1" 302 
.0.0.1 - ina [16/Aug/2021:14:37:05 +0000] "GET /token/?account=ina&scope=repository%3Aina%2Fbusybox3%3Apull%2Cpush&scope=repository%3Abusybox2%3Apull&service=localhost%3A24817 HTTP/1.0" 200
.0.0.1 - - [16/Aug/2021:14:37:05 +0000] "HEAD /v2/ina/busybox3/blobs/sha256:5b8c72934dfc08c7d2bd707e93197550f06c0751023dabb3a045b723c5e7b373 HTTP/1.1" 404 
ngo.request:WARNING: Not Found: /v2/ina/busybox3/blobs/sha256:5b8c72934dfc08c7d2bd707e93197550f06c0751023dabb3a045b723c5e7b373
.0.0.1 - ina [16/Aug/2021:14:37:05 +0000] "GET /token/?account=ina&scope=repository%3Aina%2Fbusybox3%3Apull%2Cpush&service=localhost%3A24817 HTTP/1.0" 200 
.0.0.1 - - [16/Aug/2021:14:37:05 +0000] "GET /v2/ HTTP/1.1" 401 
ngo.request:WARNING: Unauthorized: /v2/

https://docs.docker.com/search/?q=Cross%20Repository%20Blob%20Mount

As a user, I have signatures removed with the image removal

Author: @ipanova ([email protected])

Redmine Issue: 9512, https://pulp.plan.io/issues/9512


Container signature has a specific path structure base/namespaces/name@digest-algo=digest-value/signature-index

Example of the URL the client calls during signature verification process GET https://registry.redhat.io/containers/sigstore/ubi8/ubi-micro@sha256=43520d9634eaaa007a697be79eb604fcbfd348afe5e620c1407629bf20ced542/signature-1

Within the URL, index is a decimal integer (in the canonical form), starting with 1. Signatures are stored at URLs with successive index values; to read all of them, clients start with index=1, and continue reading signatures and increasing index as long as signatures with these index values exist.

Similarly, to add one more signatures to an image, one would need find the first index which does not exist, and then store the new signature using that index value.

For these reasons, it is not advised to provide a DELETE API, and the only way a signature would be removed from the sigstore would be with the image removal itself.

This is no longer true since we're adding signature api extentions. We'd still not allow signature removal api. The only way a signature would be removed from the registry would be with the image removal itself.

More info on the signature protocols https://github.com/containers/image/blob/main/docs/signature-protocols.md

Remove the interrelate stage from the sync pipeline

Author: @mdellweg (mdellweg)

Redmine Issue: 9424, https://pulp.plan.io/issues/9424


The relations between content units should be handled in the same transaction where the relating content is created.
The current approach can lead to not fully related content units in case the sync pipeline did not finish successfully.

The tools to handle this should be Content.resolution and the _post_save hook of the content stage.

By using Content.resolution we will also control the order of content that is being saved/processed in the sync pipeline, this way such errors like this will be mitigated:


Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: pulp [a2b82b5f-0427-4420-919e-b149d00c759e]: pulpcore.tasking.pulpcore_worker:INFO: Task fb0f3c7c-e537-4d15-9363-ea357f73d910 failed (null value in column "manifest_id" violates not-null constraint
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: DETAIL:  Failing row contains (34796245, null, 30fd903d-0869-4787-9743-67aa57e068ca).
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: )
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: pulp [a2b82b5f-0427-4420-919e-b149d00c759e]: pulpcore.tasking.pulpcore_worker:INFO:   File "/usr/lib/python3.6/site-packages/pulpcore/tasking/pulpcore_worker.py", line 317, in _perform_task
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: result = func(*args, **kwargs)
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/pulp_container/app/tasks/synchronize.py", line 44, in synchronize
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: return dv.create()
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/pulpcore/plugin/stages/declarative_version.py", line 151, in create
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: loop.run_until_complete(pipeline)
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib64/python3.6/asyncio/base_events.py", line 484, in run_until_complete
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: return future.result()
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/pulpcore/plugin/stages/api.py", line 225, in create_pipeline
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: await asyncio.gather(*futures)
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/pulpcore/plugin/stages/api.py", line 43, in __call__
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: await self.run()
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/pulp_container/app/tasks/sync_stages.py", line 461, in run
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: BlobManifest.objects.bulk_create(objs=blob_list, ignore_conflicts=True, batch_size=1000)
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: return getattr(self.get_queryset(), name)(*args, **kwargs)
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/django/db/models/query.py", line 474, in bulk_create
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: ids = self._batched_insert(objs_without_pk, fields, batch_size, ignore_conflicts=ignore_conflicts)
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/django/db/models/query.py", line 1211, in _batched_insert
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: self._insert(item, fields=fields, using=self.db, ignore_conflicts=ignore_conflicts)
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/django/db/models/query.py", line 1186, in _insert
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: return query.get_compiler(using=using).execute_sql(return_id)
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1377, in execute_sql
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: cursor.execute(sql, params)
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/django/db/backends/utils.py", line 67, in execute
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/django/db/backends/utils.py", line 76, in _execute_with_wrappers
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: return executor(sql, params, many, context)
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: return self.cursor.execute(sql, params)
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: raise dj_exc_value.with_traceback(traceback) from exc_value
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: File "/usr/lib/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
Nov 30 03:44:59 satellite.local pulpcore-worker-3[1231]: return self.cursor.execute(sql, params)

Nov 23 09:42:23 satellite.local pulpcore-worker-5: pulp [65351aa8-eb7b-4167-ab35-57e104b5a339]: pulpcore.tasking.pulpcore_worker:INFO: Task 7d38dc27-fb2e-489a-8895-bc250e59fe4b failed (null value in column "manifest_id" violates not-null constraint
Nov 23 09:42:23 satellite.local pulpcore-worker-5: DETAIL:  Failing row contains (41938, null, 3cdba870-bc13-4637-9e30-ae4a8d93e135).
Nov 23 09:42:23 satellite.local pulpcore-worker-5: )
Nov 23 09:42:23 satellite.local pulpcore-worker-5: pulp [65351aa8-eb7b-4167-ab35-57e104b5a339]: pulpcore.tasking.pulpcore_worker:INFO:   File "/usr/lib/python3.6/site-packages/pulpcore/tasking/pulpcore_worker.py", line 317, in _perform_task
Nov 23 09:42:23 satellite.local pulpcore-worker-5: result = func(*args, **kwargs)
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/pulp_container/app/tasks/synchronize.py", line 44, in synchronize
Nov 23 09:42:23 satellite.local pulpcore-worker-5: return dv.create()
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/pulpcore/plugin/stages/declarative_version.py", line 151, in create
Nov 23 09:42:23 satellite.local pulpcore-worker-5: loop.run_until_complete(pipeline)
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib64/python3.6/asyncio/base_events.py", line 484, in run_until_complete
Nov 23 09:42:23 satellite.local pulpcore-worker-5: return future.result()
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/pulpcore/plugin/stages/api.py", line 225, in create_pipeline
Nov 23 09:42:23 satellite.local pulpcore-worker-5: await asyncio.gather(*futures)
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/pulpcore/plugin/stages/api.py", line 43, in __call__
Nov 23 09:42:23 satellite.local pulpcore-worker-5: await self.run()
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/pulp_container/app/tasks/sync_stages.py", line 461, in run
Nov 23 09:42:23 satellite.local pulpcore-worker-5: BlobManifest.objects.bulk_create(objs=blob_list, ignore_conflicts=True, batch_size=1000)
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
Nov 23 09:42:23 satellite.local pulpcore-worker-5: return getattr(self.get_queryset(), name)(*args, **kwargs)
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/django/db/models/query.py", line 474, in bulk_create
Nov 23 09:42:23 satellite.local pulpcore-worker-5: ids = self._batched_insert(objs_without_pk, fields, batch_size, ignore_conflicts=ignore_conflicts)
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/django/db/models/query.py", line 1211, in _batched_insert
Nov 23 09:42:23 satellite.local pulpcore-worker-5: self._insert(item, fields=fields, using=self.db, ignore_conflicts=ignore_conflicts)
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/django/db/models/query.py", line 1186, in _insert
Nov 23 09:42:23 satellite.local pulpcore-worker-5: return query.get_compiler(using=using).execute_sql(return_id)
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1377, in execute_sql
Nov 23 09:42:23 satellite.local pulpcore-worker-5: cursor.execute(sql, params)
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/django/db/backends/utils.py", line 67, in execute
Nov 23 09:42:23 satellite.local pulpcore-worker-5: return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/django/db/backends/utils.py", line 76, in _execute_with_wrappers
Nov 23 09:42:23 satellite.local pulpcore-worker-5: return executor(sql, params, many, context)
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
Nov 23 09:42:23 satellite.local pulpcore-worker-5: return self.cursor.execute(sql, params)
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
Nov 23 09:42:23 satellite.local pulpcore-worker-5: raise dj_exc_value.with_traceback(traceback) from exc_value
Nov 23 09:42:23 satellite.local pulpcore-worker-5: File "/usr/lib/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
Nov 23 09:42:23 satellite.local pulpcore-worker-5: return self.cursor.execute(sql, params)

Current planning doc https://hackmd.io/zE3Nctw_QgmwIsiFKXxVgQ

As a user I can publish container signature to the server

Author: @ipanova ([email protected])

Redmine Issue: 9511, https://pulp.plan.io/issues/9511


To add a single signature, PUT a new json object with version set to 2( manifest schema version) , type set to atomic, and content set to the base64 encoded signature data (usually a GPG signed data).
Name should be set to an unique name with the form digest@per-image-name, where digest is an image manifest digest (also used in the URL), and per-image-name is any unique identifier.

$ curl -X PUT --data @signature.json http://<registry_endpoint>:24817/extensions/v2/<namespace>/<name>/signatures/<imagesha256digest>

cat signature.json

{
    "version": 2,
    "type":    "atomic",
    "name":    "sha256:4028782c08eae4a8c9a28bf661c0a8d1c2fc8e19dbaae2b018b21011197e1484@cddeb7006d914716e2728000746a0b23",
    "content": "<base64 encoded signature>",
  }

See https://github.com/openshift/openshift-docs/pull/3556/files and https://docs.openshift.com/container-platform/3.10/admin_guide/image_signatures.html#writing-image-signatures-using-registry-api

Note skopeo will upload signature given that regitry has present X-Registry-Supports-Signatures header mtrmac/image@6c17ca3

As a user I can host container image signatures

Author: @ipanova ([email protected])

Redmine Issue: 9510, https://pulp.plan.io/issues/9510


Signatures that were:

  • mirrored from remote source
  • produced by Pulp Container Registry
  • pushed into Pulp Container Registry by clients

will be available at the signature extensions API.

Add new Signature model which will have many to one relationship to the Manifest.
On manifest deletion, it's signatures will be also removed.

Q: store the signature in the DB ( it is a json file) or as an artifact? In DB

Q: store the signature as manifests part of docker v2 api ( make it cosign like, but skopeo/podman do not support that yet) we will not support this for now

As a user I can sync container image with its original signature when a sigstore is provided

Author: @ipanova ([email protected])

Redmine Issue: 9507, https://pulp.plan.io/issues/9507


Synced signatures are not verified. Signature verification is offloaded to the client.

If signed_only=True was specified only those images that have signature with be mirrored. Rest of the images will be skipped. If one of the per-arch images does not have a signature, the whole manifest list is skipped, even if some per-arch images in this list have signatures.
sigstore URL needs to be specified ( it's the webserver location of signatures, for example https://registry.redhat.io/containers/sigstore).
Otherwise it will be assumed that the signature is stored on the remote registry in a form of manifest (it most likely was signed with cosign https://github.com/SigStore/cosign#signing-subjects. we will not support this for now) or a separate object (this will be implemented as a part of different story)

Q: does podman/skopeo support verification of cosign signature type? Only atomic type for now https://github.com/containers/image/blob/main/docs/containers-signature.5.md#criticaltype

As a user during login into container registy I can authenticate against password or a token key

Author: @ipanova ([email protected])

Redmine Issue: 9115, https://pulp.plan.io/issues/9115


Allow the user to login to the registry with API tokens or a password.

podman login -u ${username} -p ${apitoken}
podman login -u ${username} -p ${password}

Approach 1

Define a custom authentication by subclassing the DRF's BaseAuthentication class.
The code flow will use most of the logic defined in the BasicAuthentication class. It will first try authenticate the current user against provided credentials as username and password and in case of failure it will then look to authenticate the user against provided token. If the provided token is associated to the current user the authentication should succeed.

class LoginView(APIView):

    authentication_classes = (CustomBasicAuthentication, JWTTokenAuthentication) 
   ....

Approach 2

Define a custom authentication class that will authenticate the current user against provided token. If the provided token is associated to the current user the authentication should succeed.

The authentication schemes are defined as a list of classes. REST framework will attempt to authenticate with each class in the list, and will set request.user and request.auth using the return value of the first class that successfully authenticates.

This custom authentication class(es) can be defined globally in DRF settings or can be used per view/viewset basis by explicitly specifying it in the view as follows:

class LoginView(APIView):

    authentication_classes = (BasicAuthentication, TokenAPIAuthentication, JWTTokenAuthentication) 
   ....

In this case it will suffice to define it in the affected views.

image_build 'artifacts' are not found during build time

Author: @dkliban ([email protected])

Redmine Issue: 6745, https://pulp.plan.io/issues/6745


$ http --auth admin:password --form :8080/pulp/api/v3/repositories/container/container/856132db-f1da-4b94-b6f2-0ee8196513ae/build_image/ containerfile@./Containerfile artifact="{\"/pulp/api/v3/artifacts/efb8d793-0bea-4d2d-9290-7846850cd802/\": \"foo/bar/example.txt\"}"

HTTP/1.1 202 Accepted
Allow: POST, OPTIONS
Connection: keep-alive
Content-Length: 67
Content-Type: application/json
Date: Thu, 14 May 2020 19:06:33 GMT
Server: nginx/1.18.0
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

{
    "task": "/pulp/api/v3/tasks/391134c2-46dc-4b01-b890-17d3d2ea9af5/"
}


$ http --auth admin:password  :8080/pulp/api/v3/tasks/391134c2-46dc-4b01-b890-17d3d2ea9af5/
HTTP/1.1 200 OK
Allow: GET, PATCH, DELETE, HEAD, OPTIONS
Connection: keep-alive
Content-Length: 1687
Content-Type: application/json
Date: Thu, 14 May 2020 19:06:52 GMT
Server: nginx/1.18.0
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

{
    "child_tasks": [],
    "created_resources": [],
    "error": {
        "description": "b'Getting image source signatures\\nCopying blob sha256:e6a50b627bcb03d96996bb8e836ecb178eae7425636e3424d9e8d33a918768dd\\nCopying config sha256:8114e7c1868bd9b15188df8c34953b151b81f90a73f16bc00aaec227bd500cc9\\nWriting manifest to image destination\\nStoring signatures\\nerror building at STEP \"COPY foo/bar/example.txt /inside-image.txt\": no files found matching \"/var/lib/pulp/tmp/13105@f9c8c543863e/391134c2-46dc-4b01-b890-17d3d2ea9af5/foo/bar/example.txt\": no such file or directory\\nlevel=error msg=\"exit status 1\"\\n'",
        "traceback": "  File \"/usr/local/lib/python3.7/site-packages/rq/worker.py\", line 886, in perform_job\n    rv = job.perform()\n  File \"/usr/local/lib/python3.7/site-packages/rq/job.py\", line 664, in perform\n    self._result = self._execute()\n  File \"/usr/local/lib/python3.7/site-packages/rq/job.py\", line 670, in _execute\n    return self.func(*self.args, **self.kwargs)\n  File \"/usr/local/lib/python3.7/site-packages/pulp_container/app/tasks/builder.py\", line 124, in build_image_from_containerfile\n    raise Exception(bud_cp.stderr)\n"
    },
    "finished_at": "2020-05-14T19:06:44.994490Z",
    "name": "pulp_container.app.tasks.builder.build_image_from_containerfile",
    "parent_task": null,
    "progress_reports": [],
    "pulp_created": "2020-05-14T19:06:33.661619Z",
    "pulp_href": "/pulp/api/v3/tasks/391134c2-46dc-4b01-b890-17d3d2ea9af5/",
    "reserved_resources_record": [
        "/pulp/api/v3/repositories/container/container/856132db-f1da-4b94-b6f2-0ee8196513ae/"
    ],
    "started_at": "2020-05-14T19:06:33.822966Z",
    "state": "failed",
    "task_group": null,
    "worker": "/pulp/api/v3/workers/81de122d-2321-4c38-9f3a-9080f7cd9bba/"
}



Validate unknown fields

Author: @lubosmj (lmjachky)

Redmine Issue: 7546, https://pulp.plan.io/issues/7546


At the moment, we do not validate unknown fields in serializers. For example, this call is executed without any errors:

http :24817/pulp/api/v3/repositories/container/container/bb221b58-bcfa-45ae-96ea-363ca381da47/tag/ tag="tag" digest=$MANIFEST_DIGEST blabla="halabala"

I propose to add the validation by leveraging pulpcore.plugin.serializers.ValidateFieldsMixin.

push operation does not save config blob with the correct media_type

Author: @ipanova ([email protected])

Redmine Issue: 9229, https://pulp.plan.io/issues/9229


After push operation Config Blob is saved with media_type from a Regular Blob. This issue does not seem to affect pull operation hence priority is not 'everything is on fire ' :)

After podman push :


In [5]: Manifest.objects.first().config_blob.media_type
Out[5]: 'application/vnd.docker.image.rootfs.diff.tar.gzip'

In [6]: Blob.objects.distinct("media_type").values_list('media_type', flat=True)
Out[6]: <QuerySet ['application/vnd.docker.image.rootfs.diff.tar.gzip']>

https://github.com/pulp/pulp_container/blob/master/pulp_container/app/registry_api.py#L685

As a user I, while mirroring, can verify image signature by providing verification policy config

Author: @ipanova ([email protected])

Redmine Issue: 9508, https://pulp.plan.io/issues/9508


Signatures are verified but not saved unless explicitly specified with-signature=True

If signature-verify=True was specified, the image signature will be verified against provided verification policy.
Only images that pass signature verification will be saved.
See https://github.com/containers/skopeo/blob/main/docs/skopeo-standalone-verify.1.md

As a user I can have repo with immutable tags

Author: @ipanova ([email protected])

Redmine Issue: 7805, https://pulp.plan.io/issues/7805


https://docs.mirantis.com/docker-enterprise/v2.1/dockeree-products/dtr/dtr-user/manage-images/prevent-tags-from-being-overwritten.html
Prevent tags from being overwritten

By default, users with read and write access to a repository can push the same tag multiple times to that repository. For example, when user A pushes an image to library/wordpress:latest, there is no preventing user B from pushing an image with the same name but a completely different functionality. This can make it difficult to trace the image back to the build that generated it.

To prevent tags from being overwritten, you can configure a repository to be immutable. Once configured,it will not be possible for anyone else to push another image tag with the same name.

Add docs that explain why repos named busybox and busybox/test cannot be pushed

Author: @ipanova ([email protected])

Redmine Issue: 8885, https://pulp.plan.io/issues/8885


User just gets 'invalid repository name' this does not get a lot of information and further guidance.

$ podman tag 6dbb9cc54074 localhost:24817/ina/tst
(pulp) [vagrant@pulp3-source-fedora32 ~]$ podman push  localhost:24817/ina/tst
Getting image source signatures
Copying blob b2d5eeeaba3a done  
Copying config 6dbb9cc540 done  
Writing manifest to image destination
Storing signatures
(pulp) [vagrant@pulp3-source-fedora32 ~]$ podman tag 6dbb9cc54074 localhost:24817/ina
(pulp) [vagrant@pulp3-source-fedora32 ~]$ podman push  localhost:24817/ina
Getting image source signatures
Copying blob b2d5eeeaba3a [--------------------------------------] 8.0b / 5.6MiB
Error: error copying image to the remote destination: Error writing blob: Error initiating layer upload to /v2/ina/blobs/uploads/ in localhost:24817: name invalid: Invalid repository name.

As a user, I can download Foreign layers

Author: [email protected] ([email protected])

Redmine Issue: 4400, https://pulp.plan.io/issues/4400


A new field was added to skip foreign layers with this issue: https://pulp.plan.io/issues/4171

The new field `include_foreign_layers` defaults to False and is not included on the Serializer, so for now it will always skip.

This story will require

  1. Add `include_foreign_layers` to the serializer
  2. add logic to download the foreign layer, which will need to retrieve the layer with an absolute url instead of a relative url.

As a user I can re-upload artifacts if the file has gone missing or corrupted

Author: @ipanova ([email protected])

Redmine Issue: 7790, https://pulp.plan.io/issues/7790


If an artifact has gone missing or corrupted(bit rot) there is no way to re-upload it back to the filesystem

  1. push an image with 'podman push'
  2. rm /var/lib/pulp/artifacts/<some_artifact> or corrupt it
  3. push same image with 'podman push'
  4. file is still missing/corrupted

Same stands for the oci image builder feature

While we have /repair/ endpoint it will not work for these operations since there is not remoteartifact.

HTTP 500 when listing distributions using browseable API

Author: @goosemania (ttereshc)

Redmine Issue: 8156, https://pulp.plan.io/issues/8156


On the RBAC branch, try to list all distributions using your browser and being logged in as admin.

http://localhost:24817/pulp/api/v3/distributions/container/container/

I get HTTP 500 and the traceback:

Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]: 127.0.0.1 - - [25/Jan/2021:18:40:18 +0000] "POST /auth/login/ HTTP/1.1" 302 0 "http://localhost:24817/auth/login/?next=/pulp/api/v3/distributions/container/container/" "Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]: pulp [7034c773c5ca4fc9a7cfd07b57b7a49e]: django.request:ERROR: Internal Server Error: /pulp/api/v3/distributions/container/container/
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]: Traceback (most recent call last):
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     response = get_response(request)
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/django/core/handlers/base.py", line 145, in _get_response
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     response = self.process_exception_by_middleware(e, request)
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/django/core/handlers/base.py", line 143, in _get_response
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     response = response.render()
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/django/template/response.py", line 106, in render
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     self.content = self.rendered_content
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/response.py", line 70, in rendered_content
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     ret = renderer.render(self.data, accepted_media_type, context)
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/renderers.py", line 724, in render
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     context = self.get_context(data, accepted_media_type, renderer_context)
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/renderers.py", line 655, in get_context
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     raw_data_post_form = self.get_raw_data_form(data, view, 'POST', request)
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/renderers.py", line 541, in get_raw_data_form
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     if not self.show_form_for_method(view, method, request, instance):
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/renderers.py", line 431, in show_form_for_method
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     view.check_permissions(request)
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/views.py", line 332, in check_permissions
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     if not permission.has_permission(request, self):
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_access_policy/access_policy.py", line 23, in has_permission
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     return self._evaluate_statements(statements, request, view, action)
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_access_policy/access_policy.py", line 59, in _evaluate_statements
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     matched = self._get_statements_matching_context_conditions(
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_access_policy/access_policy.py", line 160, in _get_statements_matching_context_conditions
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     passed = self._check_condition(condition, request, view, action)
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_access_policy/access_policy.py", line 184, in _check_condition
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     result = method(request, view, action, arg)
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:   File "/home/vagrant/devel/pulp_container/pulp_container/app/access_policy.py", line 40, in has_manage_namespace_dist_perms
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]:     namespace = request.data["base_path"].split("/")[0]
Jan 25 18:40:18 pulp3-source-fedora32.rhgoose.example.com gunicorn[23104]: KeyError: 'base_path'

Accessing it with httpie works fine.

As a user I can sign container image by providing signing policy config

Author: @ipanova ([email protected])

Redmine Issue: 9509, https://pulp.plan.io/issues/9509


As a result signature will be created and saved into the Pulp Container Registry Sigstore

It should be possible to sign whole repo, list of images or a specific image only.

See https://github.com/containers/skopeo/blob/main/docs/skopeo-standalone-sign.1.md and https://github.com/containers/image/blob/main/docs/containers-signature.5.md#json-data-format

Bindings have only one API for repository versions

Author: @goosemania (ttereshc)

Redmine Issue: 8181, https://pulp.plan.io/issues/8181


In Pulp Container there are 2 repo types, so bindings provide 2 API classes for it:
RepositoriesContainerApi
RepositoriesContainerPushApi

I'd expect to see the same for repository versions but there is only one available:
RepositoriesContainerVersionsApi

To be fair, it works with both types of repositories, however if you look at a help text for it
or try to use without all required parameters. It makes it look like it works with push repos only.

>>> repov_api = bindings.RepositoriesContainerVersionsApi(api_client)
>>> repov_api.list()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-0d222553864b> in <module>
----> 1 repov_api.list()

TypeError: list() missing 1 required positional argument: 'container_container_push_repository_href'
>>> help(repov_api.list)

Help on method list in module pulpcore.client.pulp_container.api.repositories_container_versions_api:

list(container_container_push_repository_href, **kwargs) method of pulpcore.client.pulp_container.api.repositories_container_versions_api.RepositoriesContainerVersionsApi instance
    List repository versions  # noqa: E501
    
    ContainerPushRepositoryVersion represents a single container push repository version.  Repository versions of a push repository are not allowed to be deleted. Versioning of such repositories, as well as creation/removal, happens automatically without explicit user actions. Users could make a repository not functional by accident if allowed to delete repository versions.  # noqa: E501
    This method makes a synchronous HTTP request by default. To make an
    asynchronous HTTP request, please pass async_req=True
    >>> thread = api.list(container_container_push_repository_href, async_req=True)
    >>> result = thread.get()
    
    :param async_req bool: execute request asynchronously
    :param str container_container_push_repository_href: (required)
    :param str content: content
    :param str content__in: content__in
    :param int limit: Number of results to return per page.
    :param str number: number
    :param str number__gt: number__gt
    :param str number__gte: number__gte
    :param str number__lt: number__lt
    :param str number__lte: number__lte
    :param str number__range: number__range
    :param int offset: The initial index from which to return the results.
    :param str ordering: Which field to use when ordering the results.
    :param str pulp_created: pulp_created
    :param str pulp_created__gt: pulp_created__gt
    :param str pulp_created__gte: pulp_created__gte
    :param str pulp_created__lt: pulp_created__lt
    :param str pulp_created__lte: pulp_created__lte
    :param str pulp_created__range: pulp_created__range
    :param str fields: A list of fields to include in the response.
    :param str exclude_fields: A list of fields to exclude from the response.
    :param _preload_content: if False, the urllib3.HTTPResponse object will
                             be returned without reading/decoding response
                             data. Default is True.
    :param _request_timeout: timeout setting for this request. If one
                             number provided, it will be total request
                             timeout. It can also be a pair (tuple) of
                             (connection, read) timeouts.
    :return: PaginatedRepositoryVersionResponseList
             If the method is called asynchronously,
             returns the request thread.

As an admin i can configure whether foreign layers can be pushed to the registry

Author: @ipanova ([email protected])

Redmine Issue: 6788, https://pulp.plan.io/issues/6788


Default behavior during push operations is to skip the foreign layers.
We should add possibility to be able to push foreign layers in case of air-gapped env(for example)

https://github.com/docker/docker.github.io/blob/master/registry/deploying.md#considerations-for-air-gapped-registries

Not sure if podman supports this at all

As a user I can view container image signatures

Author: @ipanova ([email protected])

Redmine Issue: 9513, https://pulp.plan.io/issues/9513


Provide an extension of the docker/distribution API.

Assuming a signed image has already been pushed into the Pulp Container Registry, one can read the signature(s)( any user with access to the image) using the following calls:

  • GET /extensions/v2/<namespace>/<name>/signatures/
  • GET /extensions/v2/<namespace>/<name>/signatures/<imagesha256digest>

See https://docs.openshift.com/container-platform/3.10/admin_guide/image_signatures.html#reading-image-signatures-via-registry-api and https://github.com/openshift/origin/pull/12504/files

As a user I can mirror a subset of platforms

Author: @ipanova ([email protected])

Redmine Issue: 7379, https://pulp.plan.io/issues/7379


A manifest list/image index can contain multiple image manifests that are build for different platforms/os.
Enable use case when a specific platform is needed to be mirrored instead of mirroring everything.

Specify the preference in the remote config . This option will not be compatible with the mirror set to True.

For pulp2pulp sync and pass-through sync
Loosen up the manifest download validation, do no fail all manifest download if we get 404 on one of the image manifests.

Dockerhub --> Pulp1(mirror selected platforms from image index )-->Pulp2(mirror all from image index)
In case of pass-through Pulp2 will get 404 on everything what was filtered out in Pulp1(do not fail the sync, continue with what's available).
The previously selected content in Pulp1ย  would pass through the request and download of images/blobs would happen from Dockerhub and passed to Pulp2.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.