Skip to content

Commit

Permalink
adding separate blobs view
Browse files Browse the repository at this point in the history
Signed-off-by: vsoch <vsochat@stanford.edu>
  • Loading branch information
vsoch committed Sep 18, 2020
1 parent 69abc86 commit 539c266
Show file tree
Hide file tree
Showing 7 changed files with 298 additions and 255 deletions.
53 changes: 28 additions & 25 deletions django_oci/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ def get_upload_folder(instance, filename):

def get_image_by_tag(name, reference):
"""given the name of a repository and a reference, look up the image
based on the reference. By default we use the reference to look for
a tag or digest. A return of None indicates that the image is not found,
and the view should raise Http404
Parameters
==========
name (str): the name of the repository to lookup
reference (str): an image tag or version
based on the reference. By default we use the reference to look for
a tag or digest. A return of None indicates that the image is not found,
and the view should raise Http404
Parameters
==========
name (str): the name of the repository to lookup
reference (str): an image tag or version
"""
if not name or not reference:
return None
Expand Down Expand Up @@ -157,7 +157,8 @@ def get_download_url(self, name):
if self.remotefile is not None:
return self.remotefile
return settings.DOMAIN_URL.strip("/") + reverse(
"django_oci:blob_download", kwargs={"digest": self.digest, "name": name},
"django_oci:blob_download",
kwargs={"digest": self.digest, "name": name},
)

def write_chunk(self, content_start, content_end, body):
Expand All @@ -172,12 +173,16 @@ def write_chunk(self, content_start, content_end, body):
raise ValueError(
"The first request for a chunked upload must start at 0."
)
datafile = ChunkedFile(name=self.digest, content=body, content_type=self.content_type)
datafile = ChunkedFile(
name=self.digest, content=body, content_type=self.content_type
)

# Uploading another chunk for existing file
else:
datafile = ChunkedFile(
name=self.digest, file=self.datafile.file, content_type=self.content_type
name=self.digest,
file=self.datafile.file,
content_type=self.content_type,
)

# Update the chunk, get back the status code
Expand All @@ -186,7 +191,6 @@ def write_chunk(self, content_start, content_end, body):
self.save()
return status_code


def create_upload_session(self):
"""A function to create an upload session for a particular blob.
The version variable will be set with a session id.
Expand All @@ -197,9 +201,7 @@ def create_upload_session(self):

# Expires in default 10 seconds
filecache.set(session_id, 1, timeout=settings.SESSION_EXPIRES_SECONDS)
return reverse(
"django_oci:blob_upload", kwargs={"session_id": session_id}
)
return reverse("django_oci:blob_upload", kwargs={"session_id": session_id})

def get_abspath(self):
return os.path.join(settings.MEDIA_ROOT, self.datafile.name)
Expand All @@ -210,9 +212,10 @@ class Meta:

class Image(models.Model):
"""An image (manifest) holds a set of layers (blobs) for a repository.
Blobs can be shared between manifests, and are deleted if they are
no longer referenced.
Blobs can be shared between manifests, and are deleted if they are
no longer referenced.
"""

add_date = models.DateTimeField("date manifest added", auto_now=True)

# When a repository is deleted, so are the manifests
Expand All @@ -224,7 +227,7 @@ class Image(models.Model):
)

# Blobs are added at the creation of the manifest (can be shared based on hash)
blobs = models.ManyToManyField(Blob, blank=True, null=True)
blobs = models.ManyToManyField(Blob)

# The text of the manifest (added at the end)
manifest = models.TextField(null=False, blank=False, default="{}")
Expand Down Expand Up @@ -275,26 +278,26 @@ class Meta:
unique_together = (
(
"repository",
"tag",
"version",
),
)


class Tag(models.Model):
"""A tag is a reference for one or more manifests
"""
"""A tag is a reference for one or more manifests"""

name = models.CharField(max_length=250, null=False, blank=False)
image = models.ForeignKey(
Image,
null=False,
blank=False,

# When a manifest is deleted, any associated tags are too
on_delete=models.CASCADE,
)


class Annotation(models.Model):
"""An annotation is a key/value pair to describe an image.
"""An annotation is a key/value pair to describe an image.
We will want to parse these from an image manifest (eventually)
"""

Expand All @@ -316,7 +319,7 @@ class Meta:
unique_together = (("key", "value"),)


#def delete_blobs(sender, instance, **kwargs):
# def delete_blobs(sender, instance, **kwargs):
# for image in instance.image_set.all():
# if hasattr(image, "datafile"):
# count = Image.objects.filter(image__datafile=image.datafile).count()
Expand All @@ -332,4 +335,4 @@ class Meta:
# by inheriting "chunked_upload.models.AbstractChunkedUpload" class
MyChunkedUpload = ChunkedUpload

#post_delete.connect(delete_blobs, sender=Image)
# post_delete.connect(delete_blobs, sender=Image)
4 changes: 3 additions & 1 deletion django_oci/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@
DOMAIN_URL = oci.get("DOMAIN_URL", DEFAULTS["DOMAIN_URL"])
MEDIA_ROOT = oci.get("MEDIA_ROOT", DEFAULTS["MEDIA_ROOT"])
CACHE_DIR = oci.get("CACHE_DIR", DEFAULTS["CACHE_DIR"])
DISABLE_TAG_MANIFEST_DELETE = oci.get("DISABLE_TAG_MANIFEST_DELETE", DEFAULTS["DISABLE_TAG_MANIFEST_DELETE"])
DISABLE_TAG_MANIFEST_DELETE = oci.get(
"DISABLE_TAG_MANIFEST_DELETE", DEFAULTS["DISABLE_TAG_MANIFEST_DELETE"]
)

SESSION_EXPIRES_SECONDS = oci.get(
"SESSION_EXPIRES_SECONDS", DEFAULTS["SESSION_EXPIRES_SECONDS"]
Expand Down
1 change: 1 addition & 0 deletions django_oci/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from django.dispatch import receiver
from .models import Image


@receiver(post_delete, sender=Image)
def delete_blobs(sender, instance, **kwargs):
print("Delete image signal running.")
Expand Down
12 changes: 8 additions & 4 deletions django_oci/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ def create_blob_request(self, name):
# Upon success, the response MUST have a code of 202 Accepted with a location header
return Response(status=202, headers={"Location": blob.create_upload_session()})


def finish_blob(
self,
blob,
Expand All @@ -86,7 +85,7 @@ def finish_blob(
"""Finish a blob, meaning finalizing the digest and returning a download
url relative to the name provided.
"""
#TODO: in the case of a blob created from upload session, need to rename to be digest
# TODO: in the case of a blob created from upload session, need to rename to be digest
blob.digest = digest
blob.save()

Expand Down Expand Up @@ -157,7 +156,9 @@ def upload_blob_chunk(
content_end (int): the content ending index
content_length (int): the content length
"""
status_code = blob.write_chunk(content_start=content_start, content_end=content_end, body=body)
status_code = blob.write_chunk(
content_start=content_start, content_end=content_end, body=body
)

# If it's already existing, return Accepted header, otherwise alert created
if status_code not in [201, 202]:
Expand All @@ -168,7 +169,6 @@ def upload_blob_chunk(
status=status_code, headers={"Location": blob.get_download_url(name)}
)


def download_blob(self, name, digest):
"""Given a blob repository name and digest, return response to stream download.
The repository name is associated to the blob via the image.
Expand All @@ -187,3 +187,7 @@ def download_blob(self, name, digest):
"Content-Disposition"
] = "inline; filename=" + os.path.basename(file_path)
return response


# Load storage on application init
storage = get_storage()
8 changes: 7 additions & 1 deletion django_oci/views/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
from .base import APIVersionCheck
from .image import ImageManifest, ImageBlobUpload, ImageBlobDownload
from .blobs import BlobUpload, BlobDownload
from .image import ImageManifest, ImageTags
from .chunked import ChunkedUploadDemo, MyChunkedUploadView, MyChunkedUploadCompleteView

# Load storage on application init
from django_oci.storage import get_storage

storage = get_storage()

0 comments on commit 539c266

Please sign in to comment.