Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Scheduled Actions #670

Merged
merged 7 commits into from
Jun 6, 2023
Merged
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
1 change: 1 addition & 0 deletions ecs_composex/ecs/helpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,4 @@ def set_families_ecs_service(settings: ComposeXSettings):
family.ecs_service.generate_service_definition(family)
family.service_scaling.create_scalable_target()
family.service_scaling.add_target_scaling()
family.service_scaling.add_scheduled_actions()
42 changes: 39 additions & 3 deletions ecs_composex/ecs/service_scaling/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@

from typing import TYPE_CHECKING

from ecs_composex.common.troposphere_tools import add_parameters, add_resource

if TYPE_CHECKING:
from ecs_composex.ecs.ecs_family import ComposeFamily

from copy import deepcopy
from json import dumps

from compose_x_common.compose_x_common import keyisset
from compose_x_common.compose_x_common import keyisset, set_else_none
from troposphere import (
AWS_ACCOUNT_ID,
AWS_PARTITION,
Expand All @@ -26,7 +25,14 @@
Sub,
applicationautoscaling,
)
from troposphere_awscommunity_applicationautoscaling_scheduledaction import (
ScalableTargetAction,
ScheduledAction,
)

from ecs_composex.common import NONALPHANUM
from ecs_composex.common.logging import LOG
from ecs_composex.common.troposphere_tools import add_resource
from ecs_composex.ecs import ecs_params

from .helpers import define_tracking_target_configuration, merge_family_services_scaling
Expand All @@ -49,6 +55,7 @@ def __init__(self, family: ComposeFamily):
self.target_scaling = None
self.scalable_target = None
self.scaling_policies = []
self.scheduled_actions: list = set_else_none("ScheduledActions", configuration)
self.replicas = max(service.replicas for service in family.services)
self.defined = False
if not keyisset("Range", configuration):
Expand Down Expand Up @@ -169,3 +176,32 @@ def add_target_scaling(self) -> None:
and policy.title not in self.family.template.resources
):
add_resource(self.family.template, policy)

def add_scheduled_actions(self) -> None:
"""Sets the scheduled actions"""
if not self.scalable_target or not self.scheduled_actions:
LOG.debug(f"services.{self.family.name}.x-scaling - No ScheduledActions")
return
for _count, _action in enumerate(self.scheduled_actions):
action = deepcopy(_action)
target_capacity = ScalableTargetAction(**action["ScalableTargetAction"])
del action["ScalableTargetAction"]
action.update(
{
"ResourceId": Ref(self.scalable_target),
"ScalableDimension": "ecs:DesiredCount",
"ServiceNamespace": "ecs",
}
)
cfn_action_title = NONALPHANUM.sub("", action["ScheduledActionName"])
scheduled_action = add_resource(
self.family.template,
ScheduledAction(
f"{self.family.logical_name}ScheduledAction{cfn_action_title}",
ScalableTargetAction=target_capacity,
**action,
),
)
LOG.debug(
f"services.{self.family.name} - Added ScheduledAction {scheduled_action.title}"
)
6 changes: 6 additions & 0 deletions ecs_composex/ecs/service_scaling/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,11 @@ def handle_defined_x_aws_autoscaling(
configs.append(service.x_scaling)


def handle_scheduled_actions(config: dict, config_name: str, definition: list) -> None:
"""Ensures all Scheduled actions defined across the services are unique"""
config[config_name] = definition


def merge_family_services_scaling(services: list[ComposeService]) -> dict:
x_scaling = {
"Range": None,
Expand All @@ -285,6 +290,7 @@ def merge_family_services_scaling(services: list[ComposeService]) -> dict:
valid_keys = [
("Range", str, handle_range),
("TargetScaling", dict, handle_target_scaling),
("ScheduledActions", list, handle_scheduled_actions),
]
for key in valid_keys:
for config in x_scaling_configs:
Expand Down
58 changes: 58 additions & 0 deletions ecs_composex/specs/services.x-scaling.spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
},
"TargetScaling": {
"$ref": "#/definitions/TargetScalingDef"
},
"ScheduledActions": {
"$ref": "#/definitions/ScheduledActions"
}
},
"definitions": {
Expand Down Expand Up @@ -76,6 +79,61 @@
"description": "Whether the scaling in should be disabled or not."
}
}
},
"ScheduledActions": {
"type": "array",
"items": {
"$ref": "#/definitions/ScheduledAction"
}
},
"ScheduledAction": {
"type": "object",
"additionalProperties": false,
"properties": {
"EndTime": {
"type": "string"
},
"ScalableTargetAction": {
"type": "object",
"additionalProperties": false,
"anyOf": [
{
"required": [
"MaxCapacity"
]
},
{
"required": [
"MinCapacity"
]
}
],
"properties": {
"MaxCapacity": {
"type": "number",
"minimum": 0
},
"MinCapacity": {
"type": "number",
"minimum": 0
}
}
},
"Schedule": {
"type": "string"
},
"ScheduledActionName": {
"type": "string",
"pattern": "^[a-zA-Z0-9-_\\.]+"
},
"StartTime": {
"type": "string"
},
"Timezone": {
"type": "string",
"default": "UTC"
}
}
}
}
}
Loading