Skip to content

Commit

Permalink
hjacobs#78: Adding support for CronJobs (hjacobs#79)
Browse files Browse the repository at this point in the history
* hjacobs#78: Adding support for CronJobs

* Fixed formatting (via black)

* Fixed broken tests

* Added test for cronjobs

* Added venv to .gitignore

* Revert "Added venv to .gitignore"

This reverts commit 4799a6b.
  • Loading branch information
fbrnc authored and hjacobs committed Jan 13, 2020
1 parent 817ae84 commit 8350694
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 35 deletions.
7 changes: 6 additions & 1 deletion kube_downscaler/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import argparse

VALID_RESOURCES = frozenset(["deployments", "statefulsets", "stacks"])
VALID_RESOURCES = frozenset(["deployments", "statefulsets", "stacks", "cronjobs"])


def check_include_resources(value):
Expand Down Expand Up @@ -80,6 +80,11 @@ def get_parser():
help="Exclude specific statefulsets from downscaling",
default=os.getenv("EXCLUDE_STATEFULSETS", ""),
)
parser.add_argument(
"--exclude-cronjobs",
help="Exclude specific cronjobs from downscaling",
default=os.getenv("EXCLUDE_CRONJOBS", ""),
)
parser.add_argument(
"--downtime-replicas",
type=int,
Expand Down
3 changes: 3 additions & 0 deletions kube_downscaler/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def main(args=None):
args.exclude_namespaces,
args.exclude_deployments,
args.exclude_statefulsets,
args.exclude_cronjobs,
args.grace_period,
args.interval,
args.dry_run,
Expand All @@ -54,6 +55,7 @@ def run_loop(
exclude_namespaces,
exclude_deployments,
exclude_statefulsets,
exclude_cronjobs,
grace_period,
interval,
dry_run,
Expand All @@ -72,6 +74,7 @@ def run_loop(
exclude_namespaces=frozenset(exclude_namespaces.split(",")),
exclude_deployments=frozenset(exclude_deployments.split(",")),
exclude_statefulsets=frozenset(exclude_statefulsets.split(",")),
exclude_cronjobs=frozenset(exclude_cronjobs.split(",")),
dry_run=dry_run,
grace_period=grace_period,
downtime_replicas=downtime_replicas,
Expand Down
121 changes: 88 additions & 33 deletions kube_downscaler/scaler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import FrozenSet

from kube_downscaler import helper
from pykube import Deployment, StatefulSet
from pykube import Deployment, StatefulSet, CronJob
from kube_downscaler.resources.stack import Stack

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -85,7 +85,6 @@ def autoscale_resource(
resource.name,
)
else:
replicas = resource.replicas
ignore = False

upscale_period = resource.annotations.get(
Expand Down Expand Up @@ -128,15 +127,29 @@ def autoscale_resource(
now, uptime
) and not helper.matches_time_spec(now, downtime)

logger.debug(
"%s %s/%s has %s replicas (original: %s, uptime: %s)",
resource.kind,
resource.namespace,
resource.name,
replicas,
original_replicas,
uptime,
)
if resource.kind == "CronJob":
suspended = resource.obj["spec"]["suspend"]
replicas = 0 if suspended else 1
logger.debug(
"%s %s/%s is %s (original: %s, uptime: %s)",
resource.kind,
resource.namespace,
resource.name,
"suspended" if suspended else "not suspended",
"suspended" if original_replicas == 0 else "not suspended",
uptime,
)
else:
replicas = resource.replicas
logger.debug(
"%s %s/%s has %s replicas (original: %s, uptime: %s)",
resource.kind,
resource.namespace,
resource.name,
replicas,
original_replicas,
uptime,
)
update_needed = False

if (
Expand All @@ -146,17 +159,30 @@ def autoscale_resource(
and original_replicas
and int(original_replicas) > 0
):
logger.info(
"Scaling up %s %s/%s from %s to %s replicas (uptime: %s, downtime: %s)",
resource.kind,
resource.namespace,
resource.name,
replicas,
original_replicas,
uptime,
downtime,
)
resource.replicas = int(original_replicas)

if resource.kind == "CronJob":
resource.obj["spec"]["suspend"] = False
resource.obj["spec"]["startingDeadlineSeconds"] = 0
logger.info(
"Unsuspending %s %s/%s (uptime: %s, downtime: %s)",
resource.kind,
resource.namespace,
resource.name,
uptime,
downtime,
)
else:
resource.replicas = int(original_replicas)
logger.info(
"Scaling up %s %s/%s from %s to %s replicas (uptime: %s, downtime: %s)",
resource.kind,
resource.namespace,
resource.name,
replicas,
original_replicas,
uptime,
downtime,
)
resource.annotations[ORIGINAL_REPLICAS_ANNOTATION] = None
update_needed = True
elif (
Expand All @@ -180,18 +206,29 @@ def autoscale_resource(
)
else:

logger.info(
"Scaling down %s %s/%s from %s to %s replicas (uptime: %s, downtime: %s)",
resource.kind,
resource.namespace,
resource.name,
replicas,
target_replicas,
uptime,
downtime,
)
if resource.kind == "CronJob":
resource.obj["spec"]["suspend"] = True
logger.info(
"Suspending %s %s/%s (uptime: %s, downtime: %s)",
resource.kind,
resource.namespace,
resource.name,
uptime,
downtime,
)
else:
resource.replicas = target_replicas
logger.info(
"Scaling down %s %s/%s from %s to %s replicas (uptime: %s, downtime: %s)",
resource.kind,
resource.namespace,
resource.name,
replicas,
target_replicas,
uptime,
downtime,
)
resource.annotations[ORIGINAL_REPLICAS_ANNOTATION] = str(replicas)
resource.replicas = target_replicas
update_needed = True
if update_needed:
if dry_run:
Expand Down Expand Up @@ -292,6 +329,7 @@ def scale(
exclude_namespaces: FrozenSet[str],
exclude_deployments: FrozenSet[str],
exclude_statefulsets: FrozenSet[str],
exclude_cronjobs: FrozenSet[str],
dry_run: bool,
grace_period: int,
downtime_replicas: int,
Expand Down Expand Up @@ -352,3 +390,20 @@ def scale(
grace_period,
downtime_replicas,
)
if "cronjobs" in include_resources:
autoscale_resources(
api,
CronJob,
namespace,
exclude_namespaces,
exclude_cronjobs,
upscale_period,
downscale_period,
default_uptime,
default_downtime,
forced_uptime,
dry_run,
now,
grace_period,
downtime_replicas,
)
Loading

0 comments on commit 8350694

Please sign in to comment.