Issue #3541

Updated by bmbouter about 2 years ago

h3. General Problem:

Some plugins have validation requirements for the membership of content units in a repository. The validation required depends on the plugin and the content type. Currently add/remove is done with a POST to v3/repositories/1234/versions/. This does not involve the plugins at all, so there is no opportunity for plugins to create these validations.

h3. Example Problem with Docker:

ManifestLists cannot be added unless the Manifests they refer to are also in the repository.
L1 is ManifestList, and it refers to (contains) 2 Manifests, M1, M2. The repository is considered corrupt if it contains L1, but not M1 and M2. M1 and M2 could be in the repository without L1.

h2. Solutions:

h3. Add a plugin opportunity to be involved Validate

The RepositoryVersion.create() method will take Allow a new, optional parameter called <code>handler</code>. A new object will be created in pulpcore.plugin.handlers.RepositoryVersionHandler. plugin to define a <code>validate_repo_version</code>

<pre><code class="python"> <pre>
class RepositoryVersionHandler: DockerManifestList(Content):

def add_content(self, qs_add_content, repo_version):

def remove_content(self, qs_remove_content, validate_repo_version(qs_content, repo_version):

def validate(self, repo_version):
Validates a repository version's DockerManifestList units.

This method specifically ensures that the repo has all the right DockerManifests that correspond

# with this method should only DockerManifestList

qs_content (django.Queryset): A Queryset of the detail instances for this content type
repo_version (RepositoryVersion): The Repository version to

django.core.exceptions.ValidationError: if the repository is invalid


def repo_key_implementation(qs_add_content, repo_version, model_class, repo_unit_key):
# the implementation check all of repo_key
# not enabled by default
# remove
the validation related DockerManifestList content form repo_version when repo_unit_key
if has_a_validation_problem:
raise ValidationException('Repo foo
has "another one" already in it. ManifestList Y but is missing Manifest Z')


h3. Add
a subclass would be: plugin add_content and remove_content

<pre><code class="python"> <pre>
class FileRepositoryVersionHandler(RepositoryVersionHandler): ModuleMD(Content):


def __init__(custom_foo, custom_bar): add_content(qa_add_content, repo_version):
Handles any extra work needed for ModuleMD content being added to a RepositoryVersion.

qs_content (django.Queryset): A Queryset of the detail instances for this content type
repo_version (RepositoryVersion): The Repository version the content is being added to

# allow for customization here from params.
check on if I need to also add some other content also

def add_content(self, qs_add_content, remove_content(qa_add_content, repo_version):
cls.repo_key_implementation(qs_add_content, repo_version, FileContent, 'relative_path')
# This effectively "enables" the repo_key functionality here instead
Handles any extra work needed for ModuleMD content being removed from a RepositoryVersion.

qs_content (django.Queryset): A Queryset
of on the Content object.

detail instances for this content type
repo_version (RepositoryVersion):
The plugin will create an instance of their subclass, e.g. <code>FileRepositoryVersionHandler</code>, configured how they want, and then pass it to RepositoryVersion.create() like:

<pre><code class="python">
Repository version the content is being removed from

# check if I should also remove corresponding RPMs
# qa_rpms_to_remove
= FileRepositoryVersionHandler('a', 'b') ...
if qa_rpms_to _remove
repo_version.remove_content(qa_rpms_to_remove, call_plugin_hook=False)


Providing It's possible we'll have a RepositoryVersionHandler is optional. recursive call

h3. Integration with DeclarativeVersion RepositoryVersion.remove_content -> ModuleMD.remove_content -> RepositoryVersion.remove_content so the 'if' statement will prevent it by not causing an additional call to ModuleMD.remove_content if there are 0 items to remove.

A new, optional The "existing add_content and remove_content": calls will receive an additional parameter called <code>handler</code> will be added <code>call_plugin_hook</code> which defaults to <code>DeclarativeVersion</code> which True. If True, the plugin callback will also accept and use the handler for various operations on the RepositoryVersion.
occur, otherwise it won't.