Add UI for viewing and changing the expiration of tags

This commit is contained in:
Joseph Schorr 2017-06-21 21:33:26 -04:00
parent 977539bf08
commit 99d7fde8ee
13 changed files with 329 additions and 26 deletions

View file

@ -0,0 +1,25 @@
"""Add change_tag_expiration log type
Revision ID: d8989249f8f6
Revises: dc4af11a5f90
Create Date: 2017-06-21 21:18:25.948689
"""
# revision identifiers, used by Alembic.
revision = 'd8989249f8f6'
down_revision = 'dc4af11a5f90'
from alembic import op
def upgrade(tables):
op.bulk_insert(tables.logentrykind, [
{'name': 'change_tag_expiration'},
])
def downgrade(tables):
op.execute(tables
.logentrykind
.delete()
.where(tables.logentrykind.c.name == op.inline_literal('change_tag_expiration')))

View file

@ -1,13 +1,17 @@
import logging
import time
from calendar import timegm
from uuid import uuid4
from peewee import IntegrityError, JOIN_LEFT_OUTER, fn
from data.model import (image, db_transaction, DataModelException, _basequery,
InvalidManifestException, TagAlreadyCreatedException, StaleTagException)
InvalidManifestException, TagAlreadyCreatedException, StaleTagException,
config)
from data.database import (RepositoryTag, Repository, Image, ImageStorage, Namespace, TagManifest,
RepositoryNotification, Label, TagManifestLabel, get_epoch_timestamp,
db_for_update)
from util.timedeltastring import convert_to_timedelta
logger = logging.getLogger(__name__)
@ -570,3 +574,41 @@ def _load_repo_manifests(namespace, repo_name):
.join(Repository)
.join(Namespace, on=(Namespace.id == Repository.namespace_user))
.where(Repository.name == repo_name, Namespace.username == namespace))
def change_repository_tag_expiration(namespace_name, repo_name, tag_name, expiration_date):
""" Changes the expiration of the tag with the given name to the given expiration datetime. If
the expiration datetime is None, then the tag is marked as not expiring.
"""
try:
tag = get_active_tag(namespace_name, repo_name, tag_name)
return change_tag_expiration(tag, expiration_date)
except RepositoryTag.DoesNotExist:
return (None, False)
def change_tag_expiration(tag, expiration_date):
""" Changes the expiration of the given tag to the given expiration datetime. If
the expiration datetime is None, then the tag is marked as not expiring.
"""
end_ts = None
min_expire_sec = convert_to_timedelta(config.app_config.get('LABELED_EXPIRATION_MINIMUM', '1h'))
max_expire_sec = convert_to_timedelta(config.app_config.get('LABELED_EXPIRATION_MAXIMUM', '104w'))
if expiration_date is not None:
offset = timegm(expiration_date.utctimetuple()) - tag.lifetime_start_ts
offset = min(max(offset, min_expire_sec.total_seconds()), max_expire_sec.total_seconds())
end_ts = tag.lifetime_start_ts + offset
if end_ts == tag.lifetime_end_ts:
return (None, True)
# Note: We check not just the ID of the tag but also its lifetime_end_ts, to ensure that it has
# not changed while we were updatings it expiration.
result = (RepositoryTag
.update(lifetime_end_ts=end_ts)
.where(RepositoryTag.id == tag.id,
RepositoryTag.lifetime_end_ts == tag.lifetime_end_ts)
.execute())
return (tag.lifetime_end_ts, result > 0)

View file

@ -1,13 +1,16 @@
import pytest
from datetime import datetime
from mock import patch
from time import time
from data.database import Image, RepositoryTag, ImageStorage, Repository
from data.model.repository import create_repository
from data.model.tag import (list_active_repo_tags, create_or_update_tag, delete_tag,
get_matching_tags, _tag_alive, get_matching_tags_for_images)
get_matching_tags, _tag_alive, get_matching_tags_for_images,
change_tag_expiration, get_active_tag)
from data.model.image import find_create_or_link_image
from util.timedeltastring import convert_to_timedelta
from test.fixtures import *
@ -177,3 +180,34 @@ def test_list_active_tags(initialized_db):
# "Move" foo by updating it and make sure we don't get duplicates.
create_or_update_tag('devtable', 'somenewrepo', 'foo', image2.docker_image_id)
assert_tags(repository, 'foo', 'bar')
@pytest.mark.parametrize('expiration_offset, expected_offset', [
(None, None),
('0s', '1h'),
('30m', '1h'),
('2h', '2h'),
('2w', '2w'),
('200w', '104w'),
])
def test_change_tag_expiration(expiration_offset, expected_offset, initialized_db):
repository = create_repository('devtable', 'somenewrepo', None)
image1 = find_create_or_link_image('foobarimage1', repository, None, {}, 'local_us')
footag = create_or_update_tag('devtable', 'somenewrepo', 'foo', image1.docker_image_id)
expiration_date = None
if expiration_offset is not None:
expiration_date = datetime.utcnow() + convert_to_timedelta(expiration_offset)
assert change_tag_expiration(footag, expiration_date)
# Lookup the tag again.
footag_updated = get_active_tag('devtable', 'somenewrepo', 'foo')
if expected_offset is None:
assert footag_updated.lifetime_end_ts is None
else:
start_date = datetime.utcfromtimestamp(footag_updated.lifetime_start_ts)
end_date = datetime.utcfromtimestamp(footag_updated.lifetime_end_ts)
expected_end_date = start_date + convert_to_timedelta(expected_offset)
assert end_date == expected_end_date