Skip to content
This repository has been archived by the owner on Oct 3, 2020. It is now read-only.

Commit

Permalink
use timezone-aware datetime for comparison with absolute timestamps (#73
Browse files Browse the repository at this point in the history
)
  • Loading branch information
kevingessner authored and hjacobs committed Oct 16, 2019
1 parent a8f1d44 commit 4376ebb
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 29 deletions.
4 changes: 2 additions & 2 deletions kube_downscaler/scaler.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@


def within_grace_period(deploy, grace_period: int, now: datetime.datetime):
creation_time = datetime.datetime.strptime(deploy.metadata['creationTimestamp'], '%Y-%m-%dT%H:%M:%SZ')
creation_time = datetime.datetime.strptime(deploy.metadata['creationTimestamp'], '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=datetime.timezone.utc)
delta = now - creation_time
return delta.total_seconds() <= grace_period

Expand Down Expand Up @@ -159,7 +159,7 @@ def scale(namespace: str, upscale_period: str, downscale_period: str,
downtime_replicas: int):
api = helper.get_kube_api()

now = datetime.datetime.utcnow()
now = datetime.datetime.now(datetime.timezone.utc)
forced_uptime = pods_force_uptime(api, namespace)

if 'deployments' in include_resources:
Expand Down
50 changes: 25 additions & 25 deletions tests/test_autoscale_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pytest
import logging

from datetime import datetime
from datetime import datetime, timezone
from pykube import Deployment
from unittest.mock import MagicMock

Expand All @@ -26,7 +26,7 @@ def test_swallow_exception(resource, caplog):
caplog.set_level(logging.ERROR)
resource.annotations = {}
resource.replicas = 1
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': 'invalid-timestamp!'}
autoscale_resource(resource, 'never', 'never', 'never', 'always', False, False, now, 0, 0)
assert resource.replicas == 1
Expand All @@ -41,7 +41,7 @@ def test_swallow_exception(resource, caplog):
def test_exclude(resource):
resource.annotations = {EXCLUDE_ANNOTATION: 'true'}
resource.replicas = 1
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'never', 'always', False, False, now, 0, 0)
assert resource.replicas == 1
Expand All @@ -52,7 +52,7 @@ def test_exclude(resource):
def test_dry_run(resource):
resource.annotations = {}
resource.replicas = 1
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'never', 'always', False, dry_run=True, now=now, grace_period=0, downtime_replicas=0)
assert resource.replicas == 0
Expand All @@ -64,7 +64,7 @@ def test_dry_run(resource):
def test_grace_period(resource):
resource.annotations = {}
resource.replicas = 1
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
# resource was only created 1 minute ago, grace period is 5 minutes
autoscale_resource(resource, 'never', 'never', 'never', 'always', False, dry_run=False, now=now, grace_period=300, downtime_replicas=0)
Expand All @@ -76,7 +76,7 @@ def test_grace_period(resource):
def test_downtime_always(resource):
resource.annotations = {EXCLUDE_ANNOTATION: 'false'}
resource.replicas = 1
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'never', 'always', False, False, now, 0, 0)
assert resource.replicas == 0
Expand All @@ -87,7 +87,7 @@ def test_downtime_always(resource):
def test_downtime_interval(resource):
resource.annotations = {EXCLUDE_ANNOTATION: 'false'}
resource.replicas = 1
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'Mon-Fri 07:30-20:30 Europe/Berlin', 'always', False, False, now, 0, 0)
assert resource.replicas == 0
Expand All @@ -98,7 +98,7 @@ def test_downtime_interval(resource):
def test_forced_uptime(resource):
resource.annotations = {EXCLUDE_ANNOTATION: 'false'}
resource.replicas = 1
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'Mon-Fri 07:30-20:30 Europe/Berlin', 'always', True, False, now, 0, 0)
assert resource.replicas == 1
Expand All @@ -108,7 +108,7 @@ def test_forced_uptime(resource):
def test_scale_up(resource):
resource.annotations = {EXCLUDE_ANNOTATION: 'false', ORIGINAL_REPLICAS_ANNOTATION: "3"}
resource.replicas = 0
now = datetime.strptime('2018-10-23T15:00:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T15:00:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'Mon-Fri 07:30-20:30 Europe/Berlin', 'never', False, False, now, 0, 0)
assert resource.replicas == 3
Expand All @@ -120,7 +120,7 @@ def test_scale_up_downtime_replicas_annotation(resource):
"""
resource.annotations = {DOWNTIME_REPLICAS_ANNOTATION: '0', ORIGINAL_REPLICAS_ANNOTATION: "1"}
resource.replicas = 0
now = datetime.strptime('2018-10-23T15:00:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T15:00:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'Mon-Fri 07:30-20:30 Europe/Berlin', 'never', False, False, now, 0, 1)
assert resource.replicas == 1
Expand All @@ -130,7 +130,7 @@ def test_scale_up_downtime_replicas_annotation(resource):
def test_downtime_replicas_annotation_invalid(resource):
resource.annotations = {DOWNTIME_REPLICAS_ANNOTATION: 'x'}
resource.replicas = 2
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'never', 'always', False, False, now, 0, 0)
assert resource.replicas == 2
Expand All @@ -140,7 +140,7 @@ def test_downtime_replicas_annotation_invalid(resource):
def test_downtime_replicas_annotation_valid(resource):
resource.annotations = {DOWNTIME_REPLICAS_ANNOTATION: '1'}
resource.replicas = 2
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'never', 'always', False, False, now, 0, 0)
assert resource.replicas == 1
Expand All @@ -150,7 +150,7 @@ def test_downtime_replicas_annotation_valid(resource):

def test_downtime_replicas_invalid(resource):
resource.replicas = 2
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'never', 'always', False, False, now, 0, "x")
assert resource.replicas == 2
Expand All @@ -159,7 +159,7 @@ def test_downtime_replicas_invalid(resource):

def test_downtime_replicas_valid(resource):
resource.replicas = 2
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'never', 'always', False, False, now, 0, 1)
assert resource.replicas == 1
Expand All @@ -171,7 +171,7 @@ def test_set_annotation():
api.config.namespace = 'myns'
resource = pykube.StatefulSet(api, {'metadata': {'name': 'foo', 'creationTimestamp': '2019-03-15T21:55:00Z'}, 'spec': {}})
resource.replicas = 1
now = datetime.strptime('2019-03-15T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2019-03-15T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
autoscale_resource(resource, 'never', 'never', 'never', 'always', False, False, now, 0, 0)
api.patch.assert_called_once()
patch_data = json.loads(api.patch.call_args[1]['data'])
Expand All @@ -183,7 +183,7 @@ def test_set_annotation():
def test_downscale_always(resource):
resource.annotations = {EXCLUDE_ANNOTATION: 'false'}
resource.replicas = 1
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'always', 'always', 'never', False, False, now, 0, 0)
assert resource.replicas == 0
Expand All @@ -194,7 +194,7 @@ def test_downscale_always(resource):
def test_downscale_period(resource):
resource.annotations = {EXCLUDE_ANNOTATION: 'false'}
resource.replicas = 1
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'Mon-Fri 20:30-24:00 Europe/Berlin', 'always', 'never', False, False, now, 0, 0)
assert resource.replicas == 0
Expand All @@ -205,7 +205,7 @@ def test_downscale_period(resource):
def test_downscale_period_overlaps(resource):
resource.annotations = {DOWNTIME_REPLICAS_ANNOTATION: '1'}
resource.replicas = 2
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'Mon-Fri 20:30-24:00 Europe/Berlin', 'Mon-Fri 20:30-24:00 Europe/Berlin', 'always', 'never', False, False, now, 0, 0)
assert resource.replicas == 2
Expand All @@ -215,7 +215,7 @@ def test_downscale_period_overlaps(resource):
def test_downscale_period_not_match(resource):
resource.annotations = {DOWNTIME_REPLICAS_ANNOTATION: '1'}
resource.replicas = 2
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'Mon-Fri 07:30-10:00 Europe/Berlin', 'always', 'never', False, False, now, 0, 0)
assert resource.replicas == 2
Expand All @@ -225,7 +225,7 @@ def test_downscale_period_not_match(resource):
def test_downscale_period_resource_overrides_never(resource):
resource.annotations = {DOWNSCALE_PERIOD_ANNOTATION: 'Mon-Fri 20:30-24:00 Europe/Berlin'}
resource.replicas = 1
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'always', 'never', False, False, now, 0, 0)
assert resource.replicas == 0
Expand All @@ -235,7 +235,7 @@ def test_downscale_period_resource_overrides_never(resource):
def test_downscale_period_resource_overrides_namespace(resource):
resource.annotations = {DOWNSCALE_PERIOD_ANNOTATION: 'Mon-Fri 20:30-24:00 Europe/Berlin'}
resource.replicas = 1
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'Mon-Fri 22:00-24:00 Europe/Berlin', 'always', 'never', False, False, now, 0, 0)
assert resource.replicas == 0
Expand All @@ -245,7 +245,7 @@ def test_downscale_period_resource_overrides_namespace(resource):
def test_upscale_period_resource_overrides_never(resource):
resource.annotations = {UPSCALE_PERIOD_ANNOTATION: 'Mon-Fri 20:30-24:00 Europe/Berlin', ORIGINAL_REPLICAS_ANNOTATION: 1}
resource.replicas = 0
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'always', 'never', False, False, now, 0, 0)
assert resource.replicas == 1
Expand All @@ -255,7 +255,7 @@ def test_upscale_period_resource_overrides_never(resource):
def test_upscale_period_resource_overrides_namespace(resource):
resource.annotations = {UPSCALE_PERIOD_ANNOTATION: 'Mon-Fri 20:30-24:00 Europe/Berlin', ORIGINAL_REPLICAS_ANNOTATION: 1}
resource.replicas = 0
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'Mon-Fri 22:00-24:00 Europe/Berlin', 'never', 'always', 'never', False, False, now, 0, 0)
assert resource.replicas == 1
Expand All @@ -277,7 +277,7 @@ def test_downscale_stack_deployment_ignored():
resource.replicas = 1
resource.annotations = {}

now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
autoscale_resource(resource, 'never', 'never', 'never', 'always', False, False, now, 0, 0)
assert resource.replicas == 1
resource.update.assert_not_called()
Expand All @@ -287,7 +287,7 @@ def test_downscale_stack_deployment_ignored():
def test_downscale_replicas_not_zero(resource):
resource.annotations = {EXCLUDE_ANNOTATION: 'false'}
resource.replicas = 3
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ')
now = datetime.strptime('2018-10-23T21:56:00Z', '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone.utc)
resource.metadata = {'creationTimestamp': '2018-10-23T21:55:00Z'}
autoscale_resource(resource, 'never', 'never', 'never', 'always', False, False, now, 0, 1)
assert resource.replicas == 1
Expand Down
4 changes: 2 additions & 2 deletions tests/test_grace_period.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from pykube import Deployment
from kube_downscaler.scaler import within_grace_period


def test_within_grace_period():
now = datetime.utcnow()
now = datetime.now(timezone.utc)
ts = now - timedelta(minutes=5)
deploy = Deployment(None, {'metadata': {'creationTimestamp': ts.strftime('%Y-%m-%dT%H:%M:%SZ')}})
assert within_grace_period(deploy, 900, now)
Expand Down

0 comments on commit 4376ebb

Please sign in to comment.