Skip to content

Commit

Permalink
ChangeSet updated for content/artifact model changes.
Browse files Browse the repository at this point in the history
closes #2942
  • Loading branch information
jortel committed Aug 10, 2017
1 parent f61019e commit 5847a68
Show file tree
Hide file tree
Showing 10 changed files with 509 additions and 188 deletions.
4 changes: 2 additions & 2 deletions docs/plugins/plugin-api/changeset.rst
Expand Up @@ -16,10 +16,10 @@ New Content & Artifacts
Classes used to define *new* content to be added to a repository.


.. autoclass:: pulpcore.plugin.changeset.RemoteContent
.. autoclass:: pulpcore.plugin.changeset.PendingContent
:members: artifacts

.. autoclass:: pulpcore.plugin.changeset.RemoteArtifact
.. autoclass:: pulpcore.plugin.changeset.PendingArtifact
:members: content


Expand Down
35 changes: 35 additions & 0 deletions platform/pulpcore/app/models/content.py
Expand Up @@ -43,6 +43,37 @@ def storage_path(self, name):
sha384 = models.CharField(max_length=96, blank=False, null=False, unique=True, db_index=True)
sha512 = models.CharField(max_length=128, blank=False, null=False, unique=True, db_index=True)

# All digest fields ordered by algorithm strength.
DIGEST_FIELDS = (
'sha512',
'sha384',
'sha256',
'sha224',
'sha1',
'md5',
)

# Reliable digest fields ordered by algorithm strength.
RELIABLE_DIGEST_FIELDS = DIGEST_FIELDS[:-3]

def is_equal(self, other):
"""
Is equal by matching digest.
Args:
other (Artifact): A artifact to match.
Returns:
bool: True when equal.
"""
for field in Artifact.RELIABLE_DIGEST_FIELDS[:-1]:
digest = getattr(self, field)
if not digest:
continue
if digest == getattr(other, field):
return True
return False


class Content(MasterModel):
"""
Expand Down Expand Up @@ -126,5 +157,9 @@ class DeferredArtifact(Model):
sha256 = models.CharField(max_length=64, blank=True, null=True)
sha384 = models.CharField(max_length=96, blank=True, null=True)
sha512 = models.CharField(max_length=128, blank=True, null=True)

content_artifact = models.ForeignKey(ContentArtifact, on_delete=models.CASCADE)
importer = models.ForeignKey('Importer', on_delete=models.CASCADE)

class Meta:
unique_together = ('content_artifact', 'importer')
30 changes: 6 additions & 24 deletions platform/pulpcore/download/validation.py
Expand Up @@ -208,25 +208,6 @@ class DigestValidation(Validation):
'md5',
)

@staticmethod
def _find_algorithm(name):
"""
Find the hash algorithm by name in hashlib.
Args:
name: The algorithm name.
Returns:
hashlib.Algorithm: The algorithm object.
Raises:
ValueError: When not found.
"""
try:
return getattr(hashlib, name.lower())()
except AttributeError:
raise ValueError(_('Algorithm {n} not supported').format(n=name))

def __init__(self, algorithm, digest, enforced=True):
"""
Args:
Expand All @@ -238,7 +219,7 @@ def __init__(self, algorithm, digest, enforced=True):
ValueError: When `algorithm` not supported by hashlib.
"""
super(DigestValidation, self).__init__(enforced)
self.algorithm = self._find_algorithm(algorithm)
self.algorithm = hashlib.new(algorithm)
self.expected = digest
self.actual = None

Expand Down Expand Up @@ -268,7 +249,8 @@ def apply(self):
log.warn(str(error))

def __str__(self):
return _(
'DigestValidation: alg={al} expected={e} actual={a}').format(al=self.algorithm,
e=self.expected,
a=self.actual)
description = _('DigestValidation: alg={al} expected={e} actual={a}')
return description.format(
al=self.algorithm,
e=self.expected,
a=self.actual)
39 changes: 18 additions & 21 deletions plugin/pulpcore/plugin/changeset/__init__.py
Expand Up @@ -3,12 +3,11 @@
The ``ChangeSet`` is the primary object used by plugin writers to support the Importer.
It represents a set of changes to be made to the repository in terms of content
that needs to be added (additions) and content that needs to be removed (removals).
The term `Remote` is used to describe the repository that the importer is synchronizing
with. The term ``RemoteContent`` is content contained in the remote repository. The
term ``RemoteArtifact`` is an artifact associated with a `RemoteContent` unit.
The term `remote` is used to describe the repository that the importer is synchronizing
with. The term ``PendingContent`` is content contained in the remote repository.
Plugin writers need to pass `additions` to the `ChangeSet` as a collection of
`RemoteContent`. In other words, `additions` are a collection of content in the remote
`PendingContent`. In other words, `additions` are a collection of content in the remote
repository that is not in the (local) Pulp repository and it needs to be added.
Plugin writers need to pass `removals` to the `ChangeSet` as a collection of `Content`
Expand Down Expand Up @@ -37,7 +36,7 @@
>>> from django.db.models import Q
>>> from collections import namedtuple
>>> from pulpcore.plugin.changeset import (
>>> ChangeSet, RemoteContent, RemoteArtifact, SizedIterable)
>>> ChangeSet, PendingArtifact, PendingContent, SizedIterable)
>>> from pulpcore.plugin.models import Artifact, Content, Importer, Repository
>>>
>>>
Expand All @@ -54,25 +53,23 @@
>>> # Using the set of additions defined by the delta and the metadata,
>>> # build and yield the content that needs to be added.
>>>
>>> for thing in metadata:
>>> for item in metadata:
>>> # Needed?
>>> if not thing.natural_key in delta.additions:
>>> if not item.natural_key in delta.additions:
>>> continue
>>> # Create a concrete model instance for Thing content
>>> # using the (thing) metadata.
>>> model = Thing(...)
>>> # Create a remote content instance using the model.
>>> content = RemoteContent(model)
>>> # Create a remote artifact for each file associated with the remote content.
>>> for file in thing:
>>> # create the artifact model instance.
>>> model = Artifact(...)
>>> # Create an object that may be used to download the file.
>>> download = self.get_download(...)
>>> # Create the remote artifact with the model instance and the download.
>>> artifact = RemoteArtifact(model, download)
>>> # Add the remote artifact to the remote content.
>>> content.artifacts.add(artifact)
>>> thing = Thing(...)
>>> # Create a pending content instance using the model along with a
>>> # pending artifact for each file associated with the content.
>>> content = PendingContent(
>>> thing,
>>> artifacts={
>>> PendingArtifact(
>>> Artifact(size=1024, sha256='...'), 'http://..', 'one.img'),
>>> PendingArtifact(
>>> Artifact(size=4888, sha256='...'), 'http://..', 'two.img'),
>>> })
>>> yield content
>>>
>>> def _fetch_removals(self, delta):
Expand Down Expand Up @@ -136,5 +133,5 @@

from .iterator import BatchIterator # noqa
from .main import ChangeSet, SizedIterable # noqa
from .model import RemoteContent, RemoteArtifact # noqa
from .model import PendingArtifact, PendingContent # noqa
from .report import ChangeReport, ChangeFailed # noqa

0 comments on commit 5847a68

Please sign in to comment.