Switch to a per-namespace configurable expiration policy for time machine, and switch the tag gc to respect it.

This commit is contained in:
Jake Moshenko 2015-02-12 14:11:56 -05:00
parent d81e6c7a4d
commit 872539bdbf
4 changed files with 26 additions and 17 deletions

View file

@ -185,8 +185,5 @@ class DefaultConfig(object):
LOG_ARCHIVE_LOCATION = 'local_us'
LOG_ARCHIVE_PATH = 'logarchive/'
# Number of revisions to keep expired tags
TIME_MACHINE_DELTA_SECONDS = 14 * 24 * 60 * 60
# For enterprise:
MAXIMUM_REPOSITORY_USAGE = 20

View file

@ -1,12 +1,14 @@
import string
import logging
import uuid
import time
from random import SystemRandom
from datetime import datetime
from peewee import *
from data.read_slave import ReadSlaveModel
from sqlalchemy.engine.url import make_url
from data.read_slave import ReadSlaveModel
from util.names import urn_generator
@ -136,6 +138,9 @@ def uuid_generator():
return str(uuid.uuid4())
_get_epoch_timestamp = lambda: int(time.time())
def close_db_filter(_):
if not db.is_closed():
logger.debug('Disconnecting from database.')
@ -175,6 +180,7 @@ class User(BaseModel):
invoice_email = BooleanField(default=False)
invalid_login_attempts = IntegerField(default=0)
last_invalid_login = DateTimeField(default=datetime.utcnow)
removed_tag_expiration_s = IntegerField(default=1209600) # Two weeks
def delete_instance(self, recursive=False, delete_nullable=False):
# If we are deleting a robot account, only execute the subset of queries necessary.
@ -456,8 +462,8 @@ class RepositoryTag(BaseModel):
name = CharField()
image = ForeignKeyField(Image)
repository = ForeignKeyField(Repository)
lifetime_start = DateTimeField(default=datetime.utcnow)
lifetime_end = DateTimeField(null=True)
lifetime_start_ts = IntegerField(default=_get_epoch_timestamp)
lifetime_end_ts = IntegerField(null=True, index=True)
class Meta:
database = db

View file

@ -2,6 +2,7 @@ import bcrypt
import logging
import dateutil.parser
import json
import time
from datetime import datetime, timedelta, date
@ -1531,8 +1532,8 @@ def get_repository_images(namespace_name, repository_name):
def _tag_alive(query):
return query.where((RepositoryTag.lifetime_end >> None) |
(RepositoryTag.lifetime_end > datetime.utcnow()))
return query.where((RepositoryTag.lifetime_end_ts >> None) |
(RepositoryTag.lifetime_end_ts > int(time.time())))
def list_repository_tags(namespace_name, repository_name):
@ -1547,14 +1548,18 @@ def list_repository_tags(namespace_name, repository_name):
def _garbage_collect_tags(namespace_name, repository_name):
with config.app_config['DB_TRANSACTION_FACTORY'](db):
repo = _get_repository(namespace_name, repository_name)
collect_time = (datetime.utcnow() -
timedelta(seconds=config.app_config['TIME_MACHINE_DELTA_SECONDS']))
to_delete = (RepositoryTag
.select(RepositoryTag.id)
.join(Repository)
.join(Namespace, on=(Repository.namespace_user == Namespace.id))
.where(Repository.name == repository_name, Namespace.username == namespace_name,
~(RepositoryTag.lifetime_end_ts >> None),
(RepositoryTag.lifetime_end_ts + Namespace.removed_tag_expiration_s) <=
int(time.time())))
(RepositoryTag
.delete()
.where(RepositoryTag.repository == repo, RepositoryTag.lifetime_end < collect_time)
.where(RepositoryTag.id << to_delete)
.execute())
@ -1745,7 +1750,7 @@ def create_or_update_tag(namespace_name, repository_name, tag_name,
except Image.DoesNotExist:
raise DataModelException('Invalid image with id: %s' % tag_docker_image_id)
now = datetime.utcnow()
now_ts = int(time.time())
try:
# When we move a tag, we really end the timeline of the old one and create a new one
@ -1753,13 +1758,14 @@ def create_or_update_tag(namespace_name, repository_name, tag_name,
.select()
.where(RepositoryTag.repository == repo, RepositoryTag.name == tag_name))
tag = query.get()
tag.lifetime_end = now
tag.lifetime_end_ts = now_ts
tag.save()
except RepositoryTag.DoesNotExist:
# No tag that needs to be ended
pass
tag = RepositoryTag.create(repository=repo, image=image, name=tag_name, lifetime_start=now)
tag = RepositoryTag.create(repository=repo, image=image, name=tag_name,
lifetime_start_ts=now_ts)
return tag
@ -1781,7 +1787,7 @@ def delete_tag(namespace_name, repository_name, tag_name):
(tag_name, namespace_name, repository_name))
raise DataModelException(msg)
found.lifetime_end = datetime.utcnow()
found.lifetime_end_ts = int(time.time())
found.save()

Binary file not shown.