diff --git a/registry.py b/registry.py index 8326d3c..686d83b 100755 --- a/registry.py +++ b/registry.py @@ -11,10 +11,11 @@ import sys import os import argparse import www_authenticate -import _strptime from datetime import timedelta, datetime as dt from getpass import getpass from multiprocessing.pool import ThreadPool +from dateutil.parser import parse +from dateutil.tz import tzutc # this is a registry manipulator, can do following: # - list all images (including layers) @@ -642,7 +643,7 @@ def delete_tags_by_age(registry, image_name, dry_run, hours, tags_to_keep): print("timestamp not found") continue - if dt.strptime(image_age[:-4], "%Y-%m-%dT%H:%M:%S.%f") < dt.now() - timedelta(hours=int(hours)): + if parse(image_age).astimezone(tzutc()) < dt.now(tzutc()) - timedelta(hours=int(hours)): print("will be deleted tag: {0} timestamp: {1}".format( tag, image_age)) tags_to_delete.append(tag) @@ -661,7 +662,7 @@ def get_newer_tags(registry, image_name, hours, tags_list): if image_age == []: print("timestamp not found") return None - if dt.strptime(image_age[:-4], "%Y-%m-%dT%H:%M:%S.%f") >= dt.now() - timedelta(hours=int(hours)): + if parse(image_age).astimezone(tzutc()) >= dt.now(tzutc()) - timedelta(hours=int(hours)): print("Keeping tag: {0} timestamp: {1}".format( tag, image_age)) return tag @@ -690,7 +691,7 @@ def get_datetime_tags(registry, image_name, tags_list): return None return { "tag": tag, - "datetime": dt.strptime(image_age[:-4], "%Y-%m-%dT%H:%M:%S.%f") + "datetime": parse(image_age).astimezone(tzutc()) } print('---------------------------------') diff --git a/requirements-build.txt b/requirements-build.txt index 749d9d5..e3946ce 100644 --- a/requirements-build.txt +++ b/requirements-build.txt @@ -1,6 +1,7 @@ certifi==2017.7.27.1 chardet==3.0.4 idna>=2.5 +python-dateutil==2.8.0 requests>=2.20.0 urllib3>=1.23 www-authenticate==0.9.2 \ No newline at end of file diff --git a/test.py b/test.py index c08ffa7..ce3f757 100644 --- a/test.py +++ b/test.py @@ -2,6 +2,8 @@ import unittest from datetime import datetime +from dateutil.tz import tzutc, tzoffset + from registry import Registry, Requests, get_tags, parse_args, \ delete_tags, delete_tags_by_age, get_error_explanation, get_newer_tags, \ keep_images_like, main_loop, get_datetime_tags, get_ordered_tags @@ -662,6 +664,18 @@ class TestDeleteTagsByAge(unittest.TestCase): delete_tags_patched.assert_called_with( self.registry, "imagename", False, ["image"], []) + @patch('registry.delete_tags') + def test_delete_tags_by_age_no_keep_with_non_utc_value(self, delete_tags_patched): + self.registry.get_image_age.return_value = "2017-12-27T12:47:33.511765448+02:00" + delete_tags_by_age(self.registry, "imagename", False, 24, []) + self.list_tags_mock.assert_called_with( + "imagename" + ) + self.list_tags_mock.assert_called_with("imagename") + self.get_tag_config_mock.assert_called_with("imagename", "image") + delete_tags_patched.assert_called_with( + self.registry, "imagename", False, ["image"], []) + @patch('registry.delete_tags') def test_delete_tags_by_age_keep_tags(self, delete_tags_patched): delete_tags_by_age(self.registry, "imagename", False, 24, ["latest"]) @@ -717,6 +731,13 @@ class TestGetNewerTags(unittest.TestCase): ["latest"] ) + def test_keep_tags_by_age_no_keep_non_utc_datetime(self): + self.registry.get_image_age.return_value = "2017-12-27T12:47:33.511765448+02:00" + self.assertEqual( + get_newer_tags(self.registry, "imagename", 23, ["latest"]), + [] + ) + class TestGetDatetimeTags(unittest.TestCase): @@ -741,7 +762,14 @@ class TestGetDatetimeTags(unittest.TestCase): def test_get_datetime_tags(self): self.assertEqual( get_datetime_tags(self.registry, "imagename", ["latest"]), - [{"tag": "latest", "datetime": datetime(2017, 12, 27, 12, 47, 33, 511765)}] + [{"tag": "latest", "datetime": datetime(2017, 12, 27, 12, 47, 33, 511765, tzinfo=tzutc())}] + ) + + def test_get_non_utc_datetime_tags(self): + self.registry.get_image_age.return_value = "2019-07-18T16:33:15.864962122+02:00" + self.assertEqual( + get_datetime_tags(self.registry, "imagename", ["latest"]), + [{"tag": "latest", "datetime": datetime(2019, 7, 18, 16, 33, 15, 864962, tzinfo=tzoffset(None, 7200))}] ) @@ -760,23 +788,23 @@ class TestGetOrderedTags(unittest.TestCase): get_datetime_tags_patched.return_value = [ { "tag": "e61d48b", - "datetime": datetime(2025, 1, 1) + "datetime": datetime(2025, 1, 1, tzinfo=tzutc()) }, { "tag": "ff24a83", - "datetime": datetime(2024, 1, 1) + "datetime": datetime(2024, 1, 1, tzinfo=tzutc()) }, { "tag": "ddd514c", - "datetime": datetime(2023, 1, 1) + "datetime": datetime(2023, 1, 1, tzinfo=tzutc()) }, { "tag": "f4ba381", - "datetime": datetime(2022, 1, 1) + "datetime": datetime(2022, 1, 1, tzinfo=tzutc()) }, { "tag": "9d5fab2", - "datetime": datetime(2021, 1, 1) + "datetime": datetime(2021, 1, 1, tzinfo=tzutc()) } ] ordered_tags = get_ordered_tags(registry="registry", image_name="image", tags_list=tags, order_by_date=True)