Merge pull request #76 from sgarcialaguna-mms/master
Dateparsing code crashes on non-UTC datetimes.
This commit is contained in:
@@ -11,10 +11,11 @@ import sys
|
|||||||
import os
|
import os
|
||||||
import argparse
|
import argparse
|
||||||
import www_authenticate
|
import www_authenticate
|
||||||
import _strptime
|
|
||||||
from datetime import timedelta, datetime as dt
|
from datetime import timedelta, datetime as dt
|
||||||
from getpass import getpass
|
from getpass import getpass
|
||||||
from multiprocessing.pool import ThreadPool
|
from multiprocessing.pool import ThreadPool
|
||||||
|
from dateutil.parser import parse
|
||||||
|
from dateutil.tz import tzutc
|
||||||
|
|
||||||
# this is a registry manipulator, can do following:
|
# this is a registry manipulator, can do following:
|
||||||
# - list all images (including layers)
|
# - 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")
|
print("timestamp not found")
|
||||||
continue
|
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(
|
print("will be deleted tag: {0} timestamp: {1}".format(
|
||||||
tag, image_age))
|
tag, image_age))
|
||||||
tags_to_delete.append(tag)
|
tags_to_delete.append(tag)
|
||||||
@@ -661,7 +662,7 @@ def get_newer_tags(registry, image_name, hours, tags_list):
|
|||||||
if image_age == []:
|
if image_age == []:
|
||||||
print("timestamp not found")
|
print("timestamp not found")
|
||||||
return None
|
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(
|
print("Keeping tag: {0} timestamp: {1}".format(
|
||||||
tag, image_age))
|
tag, image_age))
|
||||||
return tag
|
return tag
|
||||||
@@ -690,7 +691,7 @@ def get_datetime_tags(registry, image_name, tags_list):
|
|||||||
return None
|
return None
|
||||||
return {
|
return {
|
||||||
"tag": tag,
|
"tag": tag,
|
||||||
"datetime": dt.strptime(image_age[:-4], "%Y-%m-%dT%H:%M:%S.%f")
|
"datetime": parse(image_age).astimezone(tzutc())
|
||||||
}
|
}
|
||||||
|
|
||||||
print('---------------------------------')
|
print('---------------------------------')
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
certifi==2017.7.27.1
|
certifi==2017.7.27.1
|
||||||
chardet==3.0.4
|
chardet==3.0.4
|
||||||
idna>=2.5
|
idna>=2.5
|
||||||
|
python-dateutil==2.8.0
|
||||||
requests>=2.20.0
|
requests>=2.20.0
|
||||||
urllib3>=1.23
|
urllib3>=1.23
|
||||||
www-authenticate==0.9.2
|
www-authenticate==0.9.2
|
||||||
40
test.py
40
test.py
@@ -2,6 +2,8 @@ import unittest
|
|||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
from dateutil.tz import tzutc, tzoffset
|
||||||
|
|
||||||
from registry import Registry, Requests, get_tags, parse_args, \
|
from registry import Registry, Requests, get_tags, parse_args, \
|
||||||
delete_tags, delete_tags_by_age, get_error_explanation, get_newer_tags, \
|
delete_tags, delete_tags_by_age, get_error_explanation, get_newer_tags, \
|
||||||
keep_images_like, main_loop, get_datetime_tags, get_ordered_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(
|
delete_tags_patched.assert_called_with(
|
||||||
self.registry, "imagename", False, ["image"], [])
|
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')
|
@patch('registry.delete_tags')
|
||||||
def test_delete_tags_by_age_keep_tags(self, delete_tags_patched):
|
def test_delete_tags_by_age_keep_tags(self, delete_tags_patched):
|
||||||
delete_tags_by_age(self.registry, "imagename", False, 24, ["latest"])
|
delete_tags_by_age(self.registry, "imagename", False, 24, ["latest"])
|
||||||
@@ -717,6 +731,13 @@ class TestGetNewerTags(unittest.TestCase):
|
|||||||
["latest"]
|
["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):
|
class TestGetDatetimeTags(unittest.TestCase):
|
||||||
|
|
||||||
@@ -741,7 +762,14 @@ class TestGetDatetimeTags(unittest.TestCase):
|
|||||||
def test_get_datetime_tags(self):
|
def test_get_datetime_tags(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
get_datetime_tags(self.registry, "imagename", ["latest"]),
|
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 = [
|
get_datetime_tags_patched.return_value = [
|
||||||
{
|
{
|
||||||
"tag": "e61d48b",
|
"tag": "e61d48b",
|
||||||
"datetime": datetime(2025, 1, 1)
|
"datetime": datetime(2025, 1, 1, tzinfo=tzutc())
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tag": "ff24a83",
|
"tag": "ff24a83",
|
||||||
"datetime": datetime(2024, 1, 1)
|
"datetime": datetime(2024, 1, 1, tzinfo=tzutc())
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tag": "ddd514c",
|
"tag": "ddd514c",
|
||||||
"datetime": datetime(2023, 1, 1)
|
"datetime": datetime(2023, 1, 1, tzinfo=tzutc())
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tag": "f4ba381",
|
"tag": "f4ba381",
|
||||||
"datetime": datetime(2022, 1, 1)
|
"datetime": datetime(2022, 1, 1, tzinfo=tzutc())
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tag": "9d5fab2",
|
"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)
|
ordered_tags = get_ordered_tags(registry="registry", image_name="image", tags_list=tags, order_by_date=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user