Skip to content

Commit 73fa071

Browse files
G-Lenzaws-khargita
andauthored
release v3.0.2 (#564)
Co-authored-by: Kevin Hargita <[email protected]>
1 parent 98ddb98 commit 73fa071

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3001
-3624
lines changed

.projenrc.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
import { PythonProject } from "projen/lib/python";
1717

1818
function main() {
19-
new InstanceScheduler({ version: "3.0.1", cdkVersion: "2.130.0" }).synth();
19+
new InstanceScheduler({ version: "3.0.2", cdkVersion: "2.130.0" }).synth();
2020
}
2121

2222
interface InstanceSchedulerProps {

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

7+
## [3.0.2] -- 2024-07-24
8+
9+
### Fixed
10+
- Fixed an error that caused CloudFormation-managed schedules using the (now deprecated) UseMaintenanceWindow flag be an un-updatable
11+
12+
### Security
13+
- Upgrade Certifi to mitigate CVE-2024-39689
14+
15+
16+
717
## [3.0.1] -- 2024-06-27
818

919
### Changed

package-lock.json

Lines changed: 1878 additions & 1787 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

source/app/instance_scheduler/configuration/scheduling_context.py

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
# SPDX-License-Identifier: Apache-2.0
3-
import copy
43
import datetime
54
import time
65
from collections.abc import Mapping
76
from dataclasses import dataclass, field
8-
from typing import Any, Optional, TypedDict
7+
from typing import Optional, TypedDict
98
from zoneinfo import ZoneInfo
109

1110
from instance_scheduler import configuration
1211
from instance_scheduler.configuration.instance_schedule import InstanceSchedule
13-
from instance_scheduler.util.app_env import get_app_env
1412
from instance_scheduler.util.time import is_aware
1513

1614

@@ -61,40 +59,3 @@ def get_time_from_string(timestr: Optional[str]) -> Optional[datetime.time]:
6159
except ValueError:
6260
return None
6361
return datetime.time(tm.tm_hour, tm.tm_min, 0)
64-
65-
66-
def build_tags_from_template(
67-
tags_str: Any, tag_variables: Optional[Any] = None
68-
) -> list[TagTemplate]:
69-
lastkey = None
70-
tags = {}
71-
for tag in tags_str.split(","):
72-
if "=" in tag:
73-
t = tag.partition("=")
74-
tags[t[0]] = t[2]
75-
lastkey = t[0]
76-
elif lastkey is not None:
77-
tags[lastkey] = ",".join([tags[lastkey], tag])
78-
79-
tag_vars = {} if tag_variables is None else copy.copy(tag_variables)
80-
81-
dt = datetime.datetime.now(datetime.timezone.utc)
82-
tag_vars.update(
83-
{
84-
configuration.TAG_VAL_SCHEDULER: get_app_env().stack_name,
85-
configuration.TAG_VAL_YEAR: "{:0>4d}".format(dt.year),
86-
configuration.TAG_VAL_MONTH: "{:0>2d}".format(dt.month),
87-
configuration.TAG_VAL_DAY: "{:0>2d}".format(dt.day),
88-
configuration.TAG_VAL_HOUR: "{:0>2d}".format(dt.hour),
89-
configuration.TAG_VAL_MINUTE: "{:0>2d}".format(dt.minute),
90-
configuration.TAG_VAL_TIMEZONE: "UTC",
91-
}
92-
)
93-
94-
for tag in tags:
95-
value = tags[tag]
96-
if value not in ["", None]:
97-
for v in tag_vars:
98-
tags[tag] = tags[tag].replace("{{{}}}".format(v), tag_vars[v])
99-
100-
return [{"Key": t, "Value": tags[t]} for t in tags]

source/app/instance_scheduler/handler/base.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
from collections.abc import Mapping
55
from typing import TYPE_CHECKING, Any, Generic, TypeGuard, TypeVar
66

7+
from instance_scheduler.handler.environments.main_lambda_environment import (
8+
MainLambdaEnv,
9+
)
10+
711
if TYPE_CHECKING:
812
from aws_lambda_powertools.utilities.typing import LambdaContext
913
else:
@@ -12,14 +16,14 @@
1216
T = TypeVar("T")
1317

1418

15-
class Handler(ABC, Generic[T]):
19+
class MainHandler(ABC, Generic[T]):
1620
@classmethod
1721
@abstractmethod
1822
def is_handling_request(cls, event: Mapping[str, Any]) -> TypeGuard[T]:
1923
pass
2024

2125
@abstractmethod
22-
def __init__(self, event: T, context: LambdaContext) -> None:
26+
def __init__(self, event: T, context: LambdaContext, env: MainLambdaEnv) -> None:
2327
pass
2428

2529
@abstractmethod

source/app/instance_scheduler/handler/cfn_schedule.py

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
from botocore.exceptions import ClientError
88

9+
from instance_scheduler.handler.environments.main_lambda_environment import (
10+
MainLambdaEnv,
11+
)
912
from instance_scheduler.model.period_definition import PeriodDefinition
1013
from instance_scheduler.model.period_identifier import PeriodIdentifier
1114
from instance_scheduler.model.schedule_definition import ScheduleDefinition
@@ -15,7 +18,6 @@
1518
from instance_scheduler.model.store.dynamo_schedule_definition_store import (
1619
DynamoScheduleDefinitionStore,
1720
)
18-
from instance_scheduler.util.app_env import get_app_env
1921
from instance_scheduler.util.custom_resource import (
2022
CustomResource,
2123
CustomResourceRequest,
@@ -80,7 +82,6 @@ class CfnScheduleResourceProperties(TypedDict, total=False):
8082
RetainRunning: NotRequired[str]
8183
StopNewInstances: NotRequired[str]
8284
SsmMaintenanceWindow: NotRequired[list[str] | str]
83-
Metrics: NotRequired[str]
8485
OverrideStatus: NotRequired[str]
8586
Periods: NotRequired[list[CfnSchedulePeriodProperties]]
8687

@@ -98,30 +99,29 @@ def __init__(
9899
self,
99100
event: CustomResourceRequest[CfnScheduleResourceProperties],
100101
context: LambdaContext,
102+
env: MainLambdaEnv,
101103
) -> None:
102104
"""
103105
Initializes instance
104106
:param event: CFN event
105107
:param context: Lambda context
106108
"""
107109
CustomResource.__init__(self, event, context)
108-
self._logger = self._init_logger()
109-
app_env = get_app_env()
110-
self.schedule_store = DynamoScheduleDefinitionStore(app_env.config_table_name)
111-
self.period_store = DynamoPeriodDefinitionStore(app_env.config_table_name)
110+
self._logger = self._init_logger(env)
111+
self.schedule_store = DynamoScheduleDefinitionStore(env.config_table_name)
112+
self.period_store = DynamoPeriodDefinitionStore(env.config_table_name)
112113

113-
def _init_logger(self) -> Logger:
114-
app_env = get_app_env()
114+
def _init_logger(self, env: MainLambdaEnv) -> Logger:
115115
classname = self.__class__.__name__
116116
dt = datetime.now(timezone.utc)
117117
log_stream = "{}-{:0>4d}{:0>2d}{:0>2d}".format(
118118
classname, dt.year, dt.month, dt.day
119119
)
120120
return Logger(
121-
log_group=app_env.log_group,
121+
log_group=env.log_group,
122122
log_stream=log_stream,
123-
topic_arn=app_env.topic_arn,
124-
debug=app_env.enable_debug_logging,
123+
topic_arn=env.topic_arn,
124+
debug=env.enable_debug_logging,
125125
)
126126

127127
@staticmethod
@@ -200,6 +200,7 @@ def _update_request(self) -> CustomResourceResponse:
200200
schedule_def, period_defs = self._parse_schedule_template_item(
201201
self.resource_properties
202202
)
203+
203204
old_sched_def, _ = self._parse_schedule_template_item(
204205
self.old_resource_properties
205206
)
@@ -274,7 +275,7 @@ def _parse_schedule_template_item(
274275
self, resource_properties: CfnScheduleResourceProperties
275276
) -> tuple[ScheduleDefinition, list[PeriodDefinition]]:
276277
# ---------------- Validation ----------------#
277-
_validate_schedule_props_structure(resource_properties)
278+
self._validate_schedule_props_structure(resource_properties)
278279
for period_props in resource_properties.get("Periods", []):
279280
_validate_period_props_structure(period_props)
280281

@@ -345,6 +346,29 @@ def _parse_schedule_template_item(
345346

346347
return sche_def, period_defs
347348

349+
def _validate_schedule_props_structure(
350+
self, props: CfnScheduleResourceProperties
351+
) -> None:
352+
for key in props.keys():
353+
if key in {"ServiceToken", "Timeout"}:
354+
# these properties used to be part of the sample template in the IG, but have been removed in July 2023,
355+
# They do not do anything, but customers may still have old templates that include them,
356+
# so we need to not break compatibility
357+
continue
358+
359+
if key in {"UseMaintenanceWindow", "Metrics"}:
360+
# deprecated keys that no longer do anything but that not should throw errors
361+
self._logger.warning(
362+
f'Schedule contains deprecated field "${key}", this field will be ignored.'
363+
)
364+
continue
365+
366+
if key not in CfnScheduleResourceProperties.__annotations__.keys():
367+
raise InvalidScheduleConfiguration(
368+
f"Unknown schedule property {key}, valid properties are "
369+
f"{CfnScheduleResourceProperties.__annotations__.keys()}"
370+
)
371+
348372

349373
def _parse_bool(bool_str: Optional[str]) -> Optional[bool]:
350374
if bool_str is None:
@@ -384,17 +408,3 @@ def _validate_period_props_structure(props: CfnSchedulePeriodProperties) -> None
384408
f"Unknown period property {key}, valid properties are "
385409
f"{CfnSchedulePeriodProperties.__annotations__.keys()}"
386410
)
387-
388-
389-
def _validate_schedule_props_structure(props: CfnScheduleResourceProperties) -> None:
390-
for key in props.keys():
391-
if key in {"ServiceToken", "Timeout"}:
392-
# these properties used to be part of the sample template in the IG, but have been removed in July 2023,
393-
# They do not do anything, but customers may still have old templates that include them,
394-
# so we need to not break compatibility
395-
continue
396-
if key not in CfnScheduleResourceProperties.__annotations__.keys():
397-
raise InvalidScheduleConfiguration(
398-
f"Unknown schedule property {key}, valid properties are "
399-
f"{CfnScheduleResourceProperties.__annotations__.keys()}"
400-
)

source/app/instance_scheduler/handler/cli/cli_request_handler.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010
from packaging.version import Version
1111

1212
from instance_scheduler import __version__
13-
from instance_scheduler.handler.base import Handler
13+
from instance_scheduler.handler.base import MainHandler
1414
from instance_scheduler.handler.cli.schedule_usage import get_schedule_usage
15+
from instance_scheduler.handler.environments.main_lambda_environment import (
16+
MainLambdaEnv,
17+
)
1518
from instance_scheduler.model.ddb_item_utils import optionally
1619
from instance_scheduler.model.period_definition import (
1720
PeriodDefinition,
@@ -41,7 +44,6 @@
4144
)
4245
from instance_scheduler.ops_metrics.metrics import collect_metric
4346
from instance_scheduler.util import safe_json
44-
from instance_scheduler.util.app_env import get_app_env
4547
from instance_scheduler.util.logger import Logger
4648
from instance_scheduler.util.validation import ValidationException, validate_string
4749

@@ -72,36 +74,33 @@ class UnsupportedVersionException(Exception):
7274
pass
7375

7476

75-
class CliRequestHandler(Handler[AdminCliRequest]):
77+
class CliRequestHandler(MainHandler[AdminCliRequest]):
7678
"""
7779
Class to handles requests from admin CLI
7880
"""
7981

80-
def __init__(self, event: AdminCliRequest, context: LambdaContext) -> None:
82+
def __init__(
83+
self, event: AdminCliRequest, context: LambdaContext, env: MainLambdaEnv
84+
) -> None:
8185
"""
8286
Initializes handle instance
8387
:param event: event to handle
8488
:param context: lambda context
8589
"""
8690
self._event = event
8791
self._context = context
88-
self._schedule_store = DynamoScheduleDefinitionStore(
89-
get_app_env().config_table_name
90-
)
91-
self._period_store = DynamoPeriodDefinitionStore(
92-
get_app_env().config_table_name
93-
)
92+
self._schedule_store = DynamoScheduleDefinitionStore(env.config_table_name)
93+
self._period_store = DynamoPeriodDefinitionStore(env.config_table_name)
9494

9595
# Setup logging
9696
classname = self.__class__.__name__
97-
app_env = get_app_env()
9897
dt = datetime.now(timezone.utc)
9998
log_stream = LOG_STREAM.format(classname, dt.year, dt.month, dt.day)
10099
self._logger = Logger(
101-
log_group=app_env.log_group,
100+
log_group=env.log_group,
102101
log_stream=log_stream,
103-
topic_arn=app_env.topic_arn,
104-
debug=app_env.enable_debug_logging,
102+
topic_arn=env.topic_arn,
103+
debug=env.enable_debug_logging,
105104
)
106105

107106
@property

0 commit comments

Comments
 (0)