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

Commit 8350694

Browse files
fbrnchjacobs
authored andcommitted
#78: Adding support for CronJobs (#79)
* #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.
1 parent 817ae84 commit 8350694

File tree

4 files changed

+252
-35
lines changed

4 files changed

+252
-35
lines changed

kube_downscaler/cmd.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import argparse
44

5-
VALID_RESOURCES = frozenset(["deployments", "statefulsets", "stacks"])
5+
VALID_RESOURCES = frozenset(["deployments", "statefulsets", "stacks", "cronjobs"])
66

77

88
def check_include_resources(value):
@@ -80,6 +80,11 @@ def get_parser():
8080
help="Exclude specific statefulsets from downscaling",
8181
default=os.getenv("EXCLUDE_STATEFULSETS", ""),
8282
)
83+
parser.add_argument(
84+
"--exclude-cronjobs",
85+
help="Exclude specific cronjobs from downscaling",
86+
default=os.getenv("EXCLUDE_CRONJOBS", ""),
87+
)
8388
parser.add_argument(
8489
"--downtime-replicas",
8590
type=int,

kube_downscaler/main.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def main(args=None):
3636
args.exclude_namespaces,
3737
args.exclude_deployments,
3838
args.exclude_statefulsets,
39+
args.exclude_cronjobs,
3940
args.grace_period,
4041
args.interval,
4142
args.dry_run,
@@ -54,6 +55,7 @@ def run_loop(
5455
exclude_namespaces,
5556
exclude_deployments,
5657
exclude_statefulsets,
58+
exclude_cronjobs,
5759
grace_period,
5860
interval,
5961
dry_run,
@@ -72,6 +74,7 @@ def run_loop(
7274
exclude_namespaces=frozenset(exclude_namespaces.split(",")),
7375
exclude_deployments=frozenset(exclude_deployments.split(",")),
7476
exclude_statefulsets=frozenset(exclude_statefulsets.split(",")),
77+
exclude_cronjobs=frozenset(exclude_cronjobs.split(",")),
7578
dry_run=dry_run,
7679
grace_period=grace_period,
7780
downtime_replicas=downtime_replicas,

kube_downscaler/scaler.py

Lines changed: 88 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from typing import FrozenSet
55

66
from kube_downscaler import helper
7-
from pykube import Deployment, StatefulSet
7+
from pykube import Deployment, StatefulSet, CronJob
88
from kube_downscaler.resources.stack import Stack
99

1010
logger = logging.getLogger(__name__)
@@ -85,7 +85,6 @@ def autoscale_resource(
8585
resource.name,
8686
)
8787
else:
88-
replicas = resource.replicas
8988
ignore = False
9089

9190
upscale_period = resource.annotations.get(
@@ -128,15 +127,29 @@ def autoscale_resource(
128127
now, uptime
129128
) and not helper.matches_time_spec(now, downtime)
130129

131-
logger.debug(
132-
"%s %s/%s has %s replicas (original: %s, uptime: %s)",
133-
resource.kind,
134-
resource.namespace,
135-
resource.name,
136-
replicas,
137-
original_replicas,
138-
uptime,
139-
)
130+
if resource.kind == "CronJob":
131+
suspended = resource.obj["spec"]["suspend"]
132+
replicas = 0 if suspended else 1
133+
logger.debug(
134+
"%s %s/%s is %s (original: %s, uptime: %s)",
135+
resource.kind,
136+
resource.namespace,
137+
resource.name,
138+
"suspended" if suspended else "not suspended",
139+
"suspended" if original_replicas == 0 else "not suspended",
140+
uptime,
141+
)
142+
else:
143+
replicas = resource.replicas
144+
logger.debug(
145+
"%s %s/%s has %s replicas (original: %s, uptime: %s)",
146+
resource.kind,
147+
resource.namespace,
148+
resource.name,
149+
replicas,
150+
original_replicas,
151+
uptime,
152+
)
140153
update_needed = False
141154

142155
if (
@@ -146,17 +159,30 @@ def autoscale_resource(
146159
and original_replicas
147160
and int(original_replicas) > 0
148161
):
149-
logger.info(
150-
"Scaling up %s %s/%s from %s to %s replicas (uptime: %s, downtime: %s)",
151-
resource.kind,
152-
resource.namespace,
153-
resource.name,
154-
replicas,
155-
original_replicas,
156-
uptime,
157-
downtime,
158-
)
159-
resource.replicas = int(original_replicas)
162+
163+
if resource.kind == "CronJob":
164+
resource.obj["spec"]["suspend"] = False
165+
resource.obj["spec"]["startingDeadlineSeconds"] = 0
166+
logger.info(
167+
"Unsuspending %s %s/%s (uptime: %s, downtime: %s)",
168+
resource.kind,
169+
resource.namespace,
170+
resource.name,
171+
uptime,
172+
downtime,
173+
)
174+
else:
175+
resource.replicas = int(original_replicas)
176+
logger.info(
177+
"Scaling up %s %s/%s from %s to %s replicas (uptime: %s, downtime: %s)",
178+
resource.kind,
179+
resource.namespace,
180+
resource.name,
181+
replicas,
182+
original_replicas,
183+
uptime,
184+
downtime,
185+
)
160186
resource.annotations[ORIGINAL_REPLICAS_ANNOTATION] = None
161187
update_needed = True
162188
elif (
@@ -180,18 +206,29 @@ def autoscale_resource(
180206
)
181207
else:
182208

183-
logger.info(
184-
"Scaling down %s %s/%s from %s to %s replicas (uptime: %s, downtime: %s)",
185-
resource.kind,
186-
resource.namespace,
187-
resource.name,
188-
replicas,
189-
target_replicas,
190-
uptime,
191-
downtime,
192-
)
209+
if resource.kind == "CronJob":
210+
resource.obj["spec"]["suspend"] = True
211+
logger.info(
212+
"Suspending %s %s/%s (uptime: %s, downtime: %s)",
213+
resource.kind,
214+
resource.namespace,
215+
resource.name,
216+
uptime,
217+
downtime,
218+
)
219+
else:
220+
resource.replicas = target_replicas
221+
logger.info(
222+
"Scaling down %s %s/%s from %s to %s replicas (uptime: %s, downtime: %s)",
223+
resource.kind,
224+
resource.namespace,
225+
resource.name,
226+
replicas,
227+
target_replicas,
228+
uptime,
229+
downtime,
230+
)
193231
resource.annotations[ORIGINAL_REPLICAS_ANNOTATION] = str(replicas)
194-
resource.replicas = target_replicas
195232
update_needed = True
196233
if update_needed:
197234
if dry_run:
@@ -292,6 +329,7 @@ def scale(
292329
exclude_namespaces: FrozenSet[str],
293330
exclude_deployments: FrozenSet[str],
294331
exclude_statefulsets: FrozenSet[str],
332+
exclude_cronjobs: FrozenSet[str],
295333
dry_run: bool,
296334
grace_period: int,
297335
downtime_replicas: int,
@@ -352,3 +390,20 @@ def scale(
352390
grace_period,
353391
downtime_replicas,
354392
)
393+
if "cronjobs" in include_resources:
394+
autoscale_resources(
395+
api,
396+
CronJob,
397+
namespace,
398+
exclude_namespaces,
399+
exclude_cronjobs,
400+
upscale_period,
401+
downscale_period,
402+
default_uptime,
403+
default_downtime,
404+
forced_uptime,
405+
dry_run,
406+
now,
407+
grace_period,
408+
downtime_replicas,
409+
)

0 commit comments

Comments
 (0)