Change error message when trying to pull a deleted or expired tag
Will let the users know they can recover the tag via time machine Note: This was tested with the Docker protocol, but the new error code is *technically* out of spec; we should make sure its okay.
This commit is contained in:
parent
99d7fde8ee
commit
7d4fed6892
7 changed files with 39 additions and 7 deletions
|
@ -530,6 +530,15 @@ def get_active_tag(namespace, repo_name, tag_name):
|
||||||
Namespace.username == namespace)).get()
|
Namespace.username == namespace)).get()
|
||||||
|
|
||||||
|
|
||||||
|
def get_possibly_expired_tag(namespace, repo_name, tag_name):
|
||||||
|
return (RepositoryTag
|
||||||
|
.select()
|
||||||
|
.join(Repository)
|
||||||
|
.join(Namespace, on=(Repository.namespace_user == Namespace.id))
|
||||||
|
.where(RepositoryTag.name == tag_name, Repository.name == repo_name,
|
||||||
|
Namespace.username == namespace)).get()
|
||||||
|
|
||||||
|
|
||||||
def associate_generated_tag_manifest(namespace, repo_name, tag_name, manifest_digest,
|
def associate_generated_tag_manifest(namespace, repo_name, tag_name, manifest_digest,
|
||||||
manifest_data):
|
manifest_data):
|
||||||
tag = get_active_tag(namespace, repo_name, tag_name)
|
tag = get_active_tag(namespace, repo_name, tag_name)
|
||||||
|
|
|
@ -57,6 +57,13 @@ class ManifestUnknown(V2RegistryException):
|
||||||
def __init__(self, detail=None):
|
def __init__(self, detail=None):
|
||||||
super(ManifestUnknown, self).__init__('MANIFEST_UNKNOWN', 'manifest unknown', detail, 404)
|
super(ManifestUnknown, self).__init__('MANIFEST_UNKNOWN', 'manifest unknown', detail, 404)
|
||||||
|
|
||||||
|
class TagExpired(V2RegistryException):
|
||||||
|
def __init__(self, message=None, detail=None):
|
||||||
|
super(TagExpired, self).__init__('TAG_EXPIRED',
|
||||||
|
message or 'Tag has expired',
|
||||||
|
detail,
|
||||||
|
404)
|
||||||
|
|
||||||
|
|
||||||
class ManifestUnverified(V2RegistryException):
|
class ManifestUnverified(V2RegistryException):
|
||||||
def __init__(self, detail=None):
|
def __init__(self, detail=None):
|
||||||
|
|
|
@ -13,10 +13,11 @@ from endpoints.common import parse_repository_name
|
||||||
from endpoints.decorators import anon_protect
|
from endpoints.decorators import anon_protect
|
||||||
from endpoints.notificationhelper import spawn_notification
|
from endpoints.notificationhelper import spawn_notification
|
||||||
from endpoints.v2 import v2_bp, require_repo_read, require_repo_write
|
from endpoints.v2 import v2_bp, require_repo_read, require_repo_write
|
||||||
from endpoints.v2.errors import (
|
|
||||||
BlobUnknown, ManifestInvalid, ManifestUnknown, TagInvalid, NameInvalid)
|
|
||||||
from endpoints.v2.models_interface import Label
|
from endpoints.v2.models_interface import Label
|
||||||
from endpoints.v2.models_pre_oci import data_model as model
|
from endpoints.v2.models_pre_oci import data_model as model
|
||||||
|
from endpoints.v2.errors import (BlobUnknown, ManifestInvalid, ManifestUnknown, TagInvalid,
|
||||||
|
NameInvalid, TagExpired)
|
||||||
|
>>>>>>> Change error message when trying to pull a deleted or expired tag
|
||||||
from endpoints.v2.labelhandlers import handle_label
|
from endpoints.v2.labelhandlers import handle_label
|
||||||
from image.docker import ManifestException
|
from image.docker import ManifestException
|
||||||
from image.docker.schema1 import DockerSchema1Manifest, DockerSchema1ManifestBuilder
|
from image.docker.schema1 import DockerSchema1Manifest, DockerSchema1ManifestBuilder
|
||||||
|
@ -43,7 +44,14 @@ def fetch_manifest_by_tagname(namespace_name, repo_name, manifest_ref):
|
||||||
if manifest is None:
|
if manifest is None:
|
||||||
has_tag = model.has_active_tag(namespace_name, repo_name, manifest_ref)
|
has_tag = model.has_active_tag(namespace_name, repo_name, manifest_ref)
|
||||||
if not has_tag:
|
if not has_tag:
|
||||||
raise ManifestUnknown()
|
has_expired_tag = model.has_tag(namespace_name, repo_name, manifest_ref)
|
||||||
|
if has_expired_tag:
|
||||||
|
logger.debug('Found expired tag %s for repository %s/%s', manifest_ref, namespace_name,
|
||||||
|
repo_name)
|
||||||
|
msg = 'Tag %s was deleted or has expired. To pull, revive via time machine' % manifest_ref
|
||||||
|
raise TagExpired(msg)
|
||||||
|
else:
|
||||||
|
raise ManifestUnknown()
|
||||||
|
|
||||||
manifest = _generate_and_store_manifest(namespace_name, repo_name, manifest_ref)
|
manifest = _generate_and_store_manifest(namespace_name, repo_name, manifest_ref)
|
||||||
if manifest is None:
|
if manifest is None:
|
||||||
|
|
|
@ -37,6 +37,13 @@ class PreOCIModel(DockerRegistryV2DataInterface):
|
||||||
except database.RepositoryTag.DoesNotExist:
|
except database.RepositoryTag.DoesNotExist:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def has_tag(self, namespace_name, repo_name, tag_name):
|
||||||
|
try:
|
||||||
|
model.tag.get_possibly_expired_tag(namespace_name, repo_name, tag_name)
|
||||||
|
return True
|
||||||
|
except database.RepositoryTag.DoesNotExist:
|
||||||
|
return False
|
||||||
|
|
||||||
def get_manifest_by_tag(self, namespace_name, repo_name, tag_name):
|
def get_manifest_by_tag(self, namespace_name, repo_name, tag_name):
|
||||||
try:
|
try:
|
||||||
manifest = model.tag.load_tag_manifest(namespace_name, repo_name, tag_name)
|
manifest = model.tag.load_tag_manifest(namespace_name, repo_name, tag_name)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Input, Component, Inject } from 'ng-metadata/core';
|
import { Input, Component, Inject } from 'ng-metadata/core';
|
||||||
import * as moment from "moment";
|
import * as moment from "moment";
|
||||||
|
import './expiration-status-view.component.css';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A component that displays expiration status.
|
* A component that displays expiration status.
|
||||||
|
@ -16,16 +17,16 @@ export class ExpirationStatusViewComponent {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
var expiration_date = moment(expirationDate);
|
var expiration = moment(expirationDate);
|
||||||
if (moment().isAfter(expiration_date)) {
|
if (moment().isAfter(expiration)) {
|
||||||
return {'className': 'expired', 'icon': 'fa-warning'};
|
return {'className': 'expired', 'icon': 'fa-warning'};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moment().add(1, 'week').isAfter(expiration_date)) {
|
if (moment().add(1, 'week').isAfter(expiration)) {
|
||||||
return {'className': 'critical', 'icon': 'fa-warning'};
|
return {'className': 'critical', 'icon': 'fa-warning'};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moment().add(1, 'month').isAfter(expiration_date)) {
|
if (moment().add(1, 'month').isAfter(expiration)) {
|
||||||
return {'className': 'warning', 'icon': 'fa-warning'};
|
return {'className': 'warning', 'icon': 'fa-warning'};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
Reference in a new issue