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

Adding support for events #89

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions helm-chart/templates/clusterrole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ rules:
- get
- watch
- list
- apiGroups:
- ""
resources:
- events
verbs:
- get
- create
- watch
- list
- update
- patch
- apiGroups:
- extensions
- apps
Expand Down
3 changes: 3 additions & 0 deletions kube_downscaler/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,7 @@ def get_parser():
"--deployment-time-annotation",
help="Annotation that contains a resource's last deployment time, overrides creationTime. Use in combination with --grace-period.",
)
parser.add_argument(
"--enable-events", help="Enabled Events", action="store_true",
)
return parser
68 changes: 68 additions & 0 deletions kube_downscaler/helper.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import datetime
import logging
import os
import re
from typing import Match

import pykube
import pytz

logger = logging.getLogger(__name__)

WEEKDAYS = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"]

TIME_SPEC_PATTERN = re.compile(
Expand Down Expand Up @@ -67,3 +71,67 @@ def get_kube_api():
config = pykube.KubeConfig.from_env()
api = pykube.HTTPClient(config)
return api


def add_event(resource, message: str, reason: str, event_type: str, dry_run: bool):
event = (
pykube.objects.Event.objects(resource.api)
.filter(
namespace=resource.namespace,
field_selector={
"involvedObject.uid": resource.metadata.get("uid"),
"reason": reason,
"type": event_type,
},
)
.get_or_none()
)
if event and event.obj["message"] == message:
now = datetime.datetime.utcnow()
timestamp = now.strftime("%Y-%m-%dT%H:%M:%SZ")
event.obj["count"] = event.obj["count"] + 1
event.obj["lastTimestamp"] = timestamp
try:
event.update()
return event
except Exception as e:
logger.error(f"Could not update event {event.obj}: {e}")
return

return create_event(resource, message, reason, event_type, dry_run)


def create_event(resource, message: str, reason: str, event_type: str, dry_run: bool):
now = datetime.datetime.utcnow()
timestamp = now.strftime("%Y-%m-%dT%H:%M:%SZ")
event = pykube.Event(
resource.api,
{
"metadata": {
"namespace": resource.namespace,
"generateName": "kube-downscaler-",
},
"type": event_type,
"count": 1,
"firstTimestamp": timestamp,
"lastTimestamp": timestamp,
"reason": reason,
"involvedObject": {
"apiVersion": resource.version,
"name": resource.name,
"namespace": resource.namespace,
"kind": resource.kind,
"resourceVersion": resource.metadata.get("resourceVersion"),
# https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids
"uid": resource.metadata.get("uid"),
},
"message": message,
"source": {"component": "kube-downscaler"},
},
)
if not dry_run:
try:
event.create()
return event
except Exception as e:
logger.error(f"Could not create event {event.obj}: {e}")
3 changes: 3 additions & 0 deletions kube_downscaler/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def main(args=None):
args.grace_period,
args.interval,
args.dry_run,
args.enable_events,
args.downtime_replicas,
args.deployment_time_annotation,
)
Expand All @@ -60,6 +61,7 @@ def run_loop(
grace_period,
interval,
dry_run,
enable_events,
downtime_replicas,
deployment_time_annotation=None,
):
Expand All @@ -78,6 +80,7 @@ def run_loop(
exclude_statefulsets=frozenset(exclude_statefulsets.split(",")),
exclude_cronjobs=frozenset(exclude_cronjobs.split(",")),
dry_run=dry_run,
enable_events=enable_events,
grace_period=grace_period,
downtime_replicas=downtime_replicas,
deployment_time_annotation=deployment_time_annotation,
Expand Down
48 changes: 48 additions & 0 deletions kube_downscaler/scaler.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def autoscale_resource(
default_downtime: str,
forced_uptime: bool,
dry_run: bool,
enable_events: bool,
now: datetime.datetime,
grace_period: int = 0,
downtime_replicas: int = 0,
Expand Down Expand Up @@ -199,6 +200,14 @@ def autoscale_resource(
uptime,
downtime,
)
if enable_events:
helper.add_event(
resource,
"Unsuspending CronJob",
"ScaleUp",
"Normal",
dry_run,
)
else:
resource.replicas = int(original_replicas)
logger.info(
Expand All @@ -211,8 +220,17 @@ def autoscale_resource(
uptime,
downtime,
)
if enable_events:
helper.add_event(
resource,
"Scaling up replicas",
"ScaleUp",
"Normal",
dry_run,
)
resource.annotations[ORIGINAL_REPLICAS_ANNOTATION] = None
update_needed = True

elif (
not ignore
and not is_uptime
Expand Down Expand Up @@ -246,6 +264,14 @@ def autoscale_resource(
uptime,
downtime,
)
if enable_events:
helper.add_event(
resource,
"Suspending CronJob",
"ScaleDown",
"Normal",
dry_run,
)
else:
resource.replicas = target_replicas
logger.info(
Expand All @@ -258,6 +284,14 @@ def autoscale_resource(
uptime,
downtime,
)
if enable_events:
helper.add_event(
resource,
"Scaling down replicas",
"ScaleDown",
"Normal",
dry_run,
)
resource.annotations[ORIGINAL_REPLICAS_ANNOTATION] = str(replicas)
update_needed = True
if update_needed:
Expand All @@ -270,6 +304,16 @@ def autoscale_resource(
)
else:
resource.update()
except ValueError as e:
logger.exception(
"Failed to process %s %s/%s : %s",
resource.kind,
resource.namespace,
resource.name,
str(e),
)
if enable_events:
helper.add_event(resource, str(e), "ValueError", "Warning", dry_run)
except Exception as e:
logger.exception(
"Failed to process %s %s/%s : %s",
Expand All @@ -292,6 +336,7 @@ def autoscale_resources(
default_downtime: str,
forced_uptime: bool,
dry_run: bool,
enable_events: bool,
now: datetime.datetime,
grace_period: int,
downtime_replicas: int,
Expand Down Expand Up @@ -343,6 +388,7 @@ def autoscale_resources(
default_downtime_for_namespace,
forced_uptime_for_namespace,
dry_run,
enable_events,
now,
grace_period,
default_downtime_replicas_for_namespace,
Expand All @@ -363,6 +409,7 @@ def scale(
exclude_statefulsets: FrozenSet[str],
exclude_cronjobs: FrozenSet[str],
dry_run: bool,
enable_events: bool,
grace_period: int,
downtime_replicas: int,
deployment_time_annotation: Optional[str] = None,
Expand All @@ -387,6 +434,7 @@ def scale(
default_downtime,
forced_uptime,
dry_run,
enable_events,
now,
grace_period,
downtime_replicas,
Expand Down
Loading