Issue #3541

Updated by bmbouter over 4 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): 
         pass ... 

     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 validate 

             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') 

 Then </pre> 

 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. 
         pass 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"> 
 my_handler 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) 
 </code></pre> </pre> 

 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.