Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES/+task-resource-not-found.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Raised a proper `PulpException` subclass instead of a bare Django `DoesNotExist` when a task's referenced object (repository, remote, manifest, signing service, etc.) no longer exists, so the error is not sanitized away by pulpcore in a future release.
22 changes: 22 additions & 0 deletions pulp_container/app/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from rest_framework.exceptions import APIException, NotFound, ParseError

from pulpcore.plugin.exceptions import PulpException


class BadGateway(APIException):
status_code = 502
Expand Down Expand Up @@ -162,6 +164,26 @@ def __init__(self, digest):
)


class TaskResourceNotFound(PulpException):
"""Exception to signal that a resource a task depends on no longer exists.

Tasks look up their arguments' referenced objects by pk. If that object was
deleted between dispatch and execution (e.g. by a racing delete), a bare Django
DoesNotExist is not a PulpException, which pulpcore's task executor logs as
deprecated and will sanitize away in a future release. Raise this instead so the
real reason is preserved on the task result.
"""

error_code = "CON0001"

def __init__(self, message):
"""Initialize the exception with a description of the missing resource."""
self.message = message

def __str__(self):
return self.message


class InvalidRequest(ParseError):
"""An exception to render an HTTP 400 response."""

Expand Down
41 changes: 36 additions & 5 deletions pulp_container/app/tasks/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
)
from pulpcore.plugin.util import get_domain

from pulp_container.app.exceptions import TaskResourceNotFound
from pulp_container.app.models import (
Blob,
BlobManifest,
Expand Down Expand Up @@ -138,9 +139,21 @@ def build_image(
raise RuntimeError("Neither a name nor temporary file for the Containerfile was specified.")

if containerfile_tempfile_pk:
containerfile_artifact = PulpTemporaryFile.objects.get(pk=containerfile_tempfile_pk)
try:
containerfile_artifact = PulpTemporaryFile.objects.get(pk=containerfile_tempfile_pk)
except PulpTemporaryFile.DoesNotExist:
raise TaskResourceNotFound(
f"PulpTemporaryFile matching pk={containerfile_tempfile_pk} does not exist. "
"It may have been deleted after this task was dispatched."
) from None

repository = ContainerRepository.objects.get(pk=repository_pk)
try:
repository = ContainerRepository.objects.get(pk=repository_pk)
except ContainerRepository.DoesNotExist:
raise TaskResourceNotFound(
f"ContainerRepository matching pk={repository_pk} does not exist. It may "
"have been deleted after this task was dispatched."
) from None
name = str(uuid4())
with tempfile.TemporaryDirectory(dir=".") as working_directory:
working_directory = os.path.abspath(working_directory)
Expand Down Expand Up @@ -229,15 +242,33 @@ def build_image_from_containerfile(
image and tag.

"""
containerfile = Artifact.objects.get(pk=containerfile_pk)
repository = ContainerRepository.objects.get(pk=repository_pk)
try:
containerfile = Artifact.objects.get(pk=containerfile_pk)
except Artifact.DoesNotExist:
raise TaskResourceNotFound(
f"Artifact matching pk={containerfile_pk} does not exist. It may have been "
"deleted after this task was dispatched."
) from None
try:
repository = ContainerRepository.objects.get(pk=repository_pk)
except ContainerRepository.DoesNotExist:
raise TaskResourceNotFound(
f"ContainerRepository matching pk={repository_pk} does not exist. It may "
"have been deleted after this task was dispatched."
) from None
name = str(uuid4())
with tempfile.TemporaryDirectory(dir=".") as working_directory:
working_directory = os.path.abspath(working_directory)
context_path = os.path.join(working_directory, "context")
os.makedirs(context_path, exist_ok=True)
for key, val in artifacts.items():
artifact = Artifact.objects.get(pk=key)
try:
artifact = Artifact.objects.get(pk=key)
except Artifact.DoesNotExist:
raise TaskResourceNotFound(
f"Artifact matching pk={key} does not exist. It may have been "
"deleted after this task was dispatched."
) from None
dest_path = os.path.join(context_path, val)
dirs = os.path.split(dest_path)[0]
if dirs:
Expand Down
17 changes: 15 additions & 2 deletions pulp_container/app/tasks/download_image_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from pulpcore.plugin.stages import DeclarativeContent
from pulpcore.plugin.tasking import add_and_remove

from pulp_container.app.exceptions import TaskResourceNotFound
from pulp_container.app.models import ContainerRemote, ContainerRepository, Tag
from pulp_container.app.utils import determine_media_type_from_json
from pulp_container.constants import MEDIA_TYPE
Expand All @@ -21,8 +22,20 @@ async def aadd_and_remove(*args, **kwargs):


def download_image_data(repository_pk, remote_pk, raw_text_manifest_data, tag_name=None):
repository = ContainerRepository.objects.get(pk=repository_pk)
remote = ContainerRemote.objects.get(pk=remote_pk)
try:
repository = ContainerRepository.objects.get(pk=repository_pk)
except ContainerRepository.DoesNotExist:
raise TaskResourceNotFound(
f"ContainerRepository matching pk={repository_pk} does not exist. It may "
"have been deleted after this task was dispatched."
) from None
try:
remote = ContainerRemote.objects.get(pk=remote_pk)
except ContainerRemote.DoesNotExist:
raise TaskResourceNotFound(
f"ContainerRemote matching pk={remote_pk} does not exist. It may have been "
"deleted after this task was dispatched."
) from None
log.info("Pulling cache: repository={r} remote={p}".format(r=repository.name, p=remote.name))
first_stage = ContainerPullThroughFirstStage(remote, raw_text_manifest_data, tag_name)
dv = ContainerDeclarativeVersion(first_stage, repository)
Expand Down
9 changes: 8 additions & 1 deletion pulp_container/app/tasks/recursive_add.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from pulp_container.app.exceptions import TaskResourceNotFound
from pulp_container.app.models import (
MEDIA_TYPE,
Blob,
Expand All @@ -22,7 +23,13 @@ def recursive_add_content(repository_pk, content_units):
should be added to the previous Repository Version for this Repository.

"""
repository = ContainerRepository.objects.get(pk=repository_pk)
try:
repository = ContainerRepository.objects.get(pk=repository_pk)
except ContainerRepository.DoesNotExist:
raise TaskResourceNotFound(
f"ContainerRepository matching pk={repository_pk} does not exist. It may "
"have been deleted after this task was dispatched."
) from None

tags_to_add = Tag.objects.filter(pk__in=content_units)

Expand Down
9 changes: 8 additions & 1 deletion pulp_container/app/tasks/recursive_remove.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from pulpcore.plugin.models import Content, Repository

from pulp_container.app.exceptions import TaskResourceNotFound
from pulp_container.app.models import (
MEDIA_TYPE,
Blob,
Expand Down Expand Up @@ -36,7 +37,13 @@ def recursive_remove_content(repository_pk, content_units):
should be removed from the Repository.

"""
repository = Repository.objects.get(pk=repository_pk).cast()
try:
repository = Repository.objects.get(pk=repository_pk).cast()
except Repository.DoesNotExist:
raise TaskResourceNotFound(
f"Repository matching pk={repository_pk} does not exist. It may have been "
"deleted after this task was dispatched."
) from None
latest_version = repository.latest_version()
latest_content = latest_version.content.all() if latest_version else Content.objects.none()
if "*" in content_units:
Expand Down
17 changes: 15 additions & 2 deletions pulp_container/app/tasks/sign.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from pulpcore.plugin.models import Repository

from pulp_container.app.exceptions import TaskResourceNotFound
from pulp_container.app.models import (
ManifestSignature,
ManifestSigningService,
Expand Down Expand Up @@ -41,7 +42,13 @@ def sign(repository_pk, signing_service_pk, reference, tags_list=None):
should be signed.

"""
repository = Repository.objects.get(pk=repository_pk).cast()
try:
repository = Repository.objects.get(pk=repository_pk).cast()
except Repository.DoesNotExist:
raise TaskResourceNotFound(
f"Repository matching pk={repository_pk} does not exist. It may have been "
"deleted after this task was dispatched."
) from None
latest_version = repository.latest_version()
if tags_list:
latest_repo_content_tags = latest_version.content.filter(
Expand All @@ -55,7 +62,13 @@ def sign(repository_pk, signing_service_pk, reference, tags_list=None):
.select_related("tagged_manifest")
.exclude(Q(name__endswith=".sig") | Q(name__endswith=".att") | Q(name__endswith=".sbom"))
)
signing_service = ManifestSigningService.objects.get(pk=signing_service_pk)
try:
signing_service = ManifestSigningService.objects.get(pk=signing_service_pk)
except ManifestSigningService.DoesNotExist:
raise TaskResourceNotFound(
f"ManifestSigningService matching pk={signing_service_pk} does not exist. "
"It may have been deleted after this task was dispatched."
) from None

async def sign_manifests():
added_signatures = []
Expand Down
17 changes: 15 additions & 2 deletions pulp_container/app/tasks/synchronize.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
ResolveContentFutures,
)

from pulp_container.app.exceptions import TaskResourceNotFound
from pulp_container.app.models import ContainerRemote, ContainerRepository

from .sync_stages import ContainerContentSaver, ContainerFirstStage
Expand All @@ -34,8 +35,20 @@ def synchronize(remote_pk, repository_pk, mirror, signed_only):
ValueError: If the remote does not specify a URL to sync

"""
remote = ContainerRemote.objects.get(pk=remote_pk)
repository = ContainerRepository.objects.get(pk=repository_pk)
try:
remote = ContainerRemote.objects.get(pk=remote_pk)
except ContainerRemote.DoesNotExist:
raise TaskResourceNotFound(
f"ContainerRemote matching pk={remote_pk} does not exist. It may have been "
"deleted after this task was dispatched."
) from None
try:
repository = ContainerRepository.objects.get(pk=repository_pk)
except ContainerRepository.DoesNotExist:
raise TaskResourceNotFound(
f"ContainerRepository matching pk={repository_pk} does not exist. It may "
"have been deleted after this task was dispatched."
) from None
log.info("Synchronizing: repository={r} remote={p}".format(r=repository.name, p=remote.name))
first_stage = ContainerFirstStage(remote, signed_only)
dv = ContainerDeclarativeVersion(first_stage, repository, mirror)
Expand Down
19 changes: 16 additions & 3 deletions pulp_container/app/tasks/tag.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pulpcore.plugin.models import CreatedResource, Repository
from pulpcore.plugin.util import get_domain

from pulp_container.app.exceptions import TaskResourceNotFound
from pulp_container.app.models import Manifest, Tag


Expand All @@ -14,9 +15,21 @@ def tag_image(manifest_pk, tag, repository_pk):
a new repository version when a manifest contains a digest which is not equal to the
digest passed with POST request.
"""
manifest = Manifest.objects.get(pk=manifest_pk)

repository = Repository.objects.get(pk=repository_pk).cast()
try:
manifest = Manifest.objects.get(pk=manifest_pk)
except Manifest.DoesNotExist:
raise TaskResourceNotFound(
f"Manifest matching pk={manifest_pk} does not exist. It may have been "
"deleted after this task was dispatched."
) from None

try:
repository = Repository.objects.get(pk=repository_pk).cast()
except Repository.DoesNotExist:
raise TaskResourceNotFound(
f"Repository matching pk={repository_pk} does not exist. It may have been "
"deleted after this task was dispatched."
) from None
latest_version = repository.latest_version()

tags_to_remove = Tag.objects.filter(pk__in=latest_version.content.all(), name=tag).exclude(
Expand Down
9 changes: 8 additions & 1 deletion pulp_container/app/tasks/untag.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
from pulpcore.plugin.models import Repository

from pulp_container.app.exceptions import TaskResourceNotFound
from pulp_container.app.models import Tag


def untag_image(tag, repository_pk):
"""
Create a new repository version without a specified manifest's tag name.
"""
repository = Repository.objects.get(pk=repository_pk).cast()
try:
repository = Repository.objects.get(pk=repository_pk).cast()
except Repository.DoesNotExist:
raise TaskResourceNotFound(
f"Repository matching pk={repository_pk} does not exist. It may have been "
"deleted after this task was dispatched."
) from None
latest_version = repository.latest_version()

tags_in_latest_repository = latest_version.content.filter(pulp_type=Tag.get_pulp_type())
Expand Down
Loading