1
1
import json
2
2
import logging
3
3
import logging .config
4
+ from dataclasses import dataclass
4
5
from os import environ
5
6
6
7
import boto3
@@ -20,16 +21,29 @@ class InstanceRefreshInProgress(LambdaError):
20
21
pass
21
22
22
23
24
+ class MissingEnvironmentVariable (LambdaError ):
25
+ pass
26
+
27
+
28
+ @dataclass
29
+ class LaunchTemplate :
30
+
31
+ is_arm : bool
32
+ name : str
33
+
34
+
35
+ AUTO_SCALING_GROUP_IS_ARM_DEFAULT = environ ['AUTO_SCALING_GROUP_IS_ARM_DEFAULT' ] == 'True'
23
36
AUTO_SCALING_GROUP_NAME = environ ['AUTO_SCALING_GROUP_NAME' ]
24
37
DESCRIBE_INSTANCE_REFRESHES_MAX_RECORDS = int (environ ['DESCRIBE_INSTANCE_REFRESHES_MAX_RECORDS' ])
25
38
FINISHED_INSTANCE_REFRESH_STATES = ('Cancelled' , 'Failed' , 'Successful' )
26
39
LOGGING_LEVEL = environ .get ('LOGGING_LEVEL' , logging .INFO )
27
40
REFRESH_INSTANCE_WARMUP = int (environ ['REFRESH_INSTANCE_WARMUP' ])
28
41
REFRESH_MIN_HEALTHY_PERCENTAGE = int (environ ['REFRESH_MIN_HEALTHY_PERCENTAGE' ])
29
- REFRESH_SKIP_MATCHING = bool ( environ ['REFRESH_SKIP_MATCHING' ])
42
+ REFRESH_SKIP_MATCHING = environ ['REFRESH_SKIP_MATCHING' ] == 'True'
30
43
SENTRY_DSN = environ .get ('SENTRY_DSN' )
31
44
SSM_PARAMETER_NAME = environ ['SSM_PARAMETER_NAME' ]
32
- UPDATE_MIXED_INSTANCES_POLICY_OVERRIDEN_LAUNCH_TEMPLATES = bool (environ ['UPDATE_MIXED_OVERRIDE_LAUNCH_TEMPLATES' ])
45
+ SSM_PARAMETER_NAME_ARM = environ .get ('SSM_PARAMETER_NAME_ARM' )
46
+ UPDATE_MIXED_INSTANCES_POLICY_OVERRIDEN_LAUNCH_TEMPLATES = environ ['UPDATE_MIXED_OVERRIDE_LAUNCH_TEMPLATES' ] == 'True'
33
47
34
48
if SENTRY_DSN :
35
49
sentry_sdk .init (SENTRY_DSN , integrations = [AwsLambdaIntegration ()])
@@ -59,10 +73,10 @@ class InstanceRefreshInProgress(LambdaError):
59
73
ssm = boto3 .client ('ssm' )
60
74
61
75
62
- def get_current_image_id ():
76
+ def get_current_image_id (ssm_parameter_name ):
63
77
"""Returns current AMI from SSM"""
64
78
param_value = None
65
- param = ssm .get_parameter (Name = SSM_PARAMETER_NAME )
79
+ param = ssm .get_parameter (Name = ssm_parameter_name )
66
80
value = param ['Parameter' ]['Value' ]
67
81
if value .startswith ('ami-' ):
68
82
image_id = value
@@ -73,36 +87,43 @@ def get_current_image_id():
73
87
return image_id
74
88
75
89
76
- def get_launch_template_names_and_auto_scaling_group ( ):
90
+ def get_launch_templates ( auto_scaling_group_names ):
77
91
"""Returns Launch Template names for Auto Scaling Group"""
78
- group_description_resp = autoscaling .describe_auto_scaling_groups (AutoScalingGroupNames = ( AUTO_SCALING_GROUP_NAME ,) )
92
+ group_description_resp = autoscaling .describe_auto_scaling_groups (AutoScalingGroupNames = auto_scaling_group_names )
79
93
group_details = group_description_resp ['AutoScalingGroups' ][0 ]
80
94
mixed_instances_policy = group_details ['MixedInstancesPolicy' ]
81
- launch_template_names = []
95
+ launch_templates = []
82
96
83
97
if 'MixedInstancesPolicy' in group_details :
84
98
launch_template_details = mixed_instances_policy ['LaunchTemplate' ]
85
- launch_template_names .append (launch_template_details ['LaunchTemplateSpecification' ]['LaunchTemplateName' ])
99
+ launch_templates .append (
100
+ LaunchTemplate (AUTO_SCALING_GROUP_IS_ARM_DEFAULT ,
101
+ launch_template_details ['LaunchTemplateSpecification' ]['LaunchTemplateName' ]),
102
+ )
86
103
87
104
if UPDATE_MIXED_INSTANCES_POLICY_OVERRIDEN_LAUNCH_TEMPLATES :
88
105
overrides = launch_template_details ['Overrides' ]
89
106
for override in overrides :
107
+ instance_type_parts = override ['InstanceType' ].split ('.' )
108
+ is_instance_type_arm = instance_type_parts [0 ].endswith ('g' )
90
109
if override_lt_specification := override .get ('LaunchTemplateSpecification' ):
91
110
if override_lt_name := override_lt_specification .get ('LaunchTemplateName' ):
92
- launch_template_names .append (override_lt_name )
111
+ launch_templates .append (LaunchTemplate ( is_instance_type_arm , override_lt_name ) )
93
112
else :
94
- launch_template_names .append (group_details ['LaunchTemplate' ]['LaunchTemplateName' ])
113
+ launch_templates .append (
114
+ LaunchTemplate (AUTO_SCALING_GROUP_IS_ARM_DEFAULT , group_details ['LaunchTemplate' ]['LaunchTemplateName' ]),
115
+ )
95
116
96
- logger .info ('Using Launch Templates "%s"' , launch_template_names )
97
- return ( launch_template_names , group_description_resp [ 'AutoScalingGroups' ][ 0 ])
117
+ logger .info ('Using Launch Templates "%s"' , launch_templates )
118
+ return launch_templates
98
119
99
120
100
- def is_launch_template_updated (image_id , launch_template_name ):
121
+ def is_launch_template_updated (image_id , launch_template ):
101
122
"""Checks consistency between $Default and $Latest versions of Launch Template and returns bool wheter versions
102
123
match
103
124
"""
104
125
default_and_latest_versions = ec2 .describe_launch_template_versions (
105
- LaunchTemplateName = launch_template_name ,
126
+ LaunchTemplateName = launch_template . name ,
106
127
Versions = ('$Default' , '$Latest' ),
107
128
)
108
129
if (size := len (default_and_latest_versions )) != 2 :
@@ -176,19 +197,25 @@ def start_instance_refresh():
176
197
177
198
178
199
def main ():
179
- image_id = get_current_image_id ()
180
- launch_template_names , autoscaling_group = get_launch_template_names_and_auto_scaling_group ()
200
+ image_id = get_current_image_id (SSM_PARAMETER_NAME )
201
+ image_id_arm = get_current_image_id (SSM_PARAMETER_NAME_ARM ) if SSM_PARAMETER_NAME_ARM else None
202
+
203
+ launch_templates = get_launch_templates ((AUTO_SCALING_GROUP_NAME ,))
181
204
all_templates_up_to_date = True
182
205
183
- for launch_template_name in launch_template_names :
184
- if not is_launch_template_updated (image_id , launch_template_name ):
206
+ for launch_template in launch_templates :
207
+ if launch_template .is_arm and not image_id_arm :
208
+ raise MissingEnvironmentVariable ('Set the "SSM_PARAMETER_NAME_ARM" environment variable' )
209
+ lt_image_id = image_id_arm if launch_template .is_arm else image_id
210
+
211
+ if not is_launch_template_updated (lt_image_id , launch_template ):
185
212
all_templates_up_to_date = False
186
213
logger .info ('Launch Template "%s" for Auto Scaling Group "%s" is not up to date' ,
187
- launch_template_name , AUTO_SCALING_GROUP_NAME )
188
- update_launch_template (image_id , launch_template_name )
214
+ launch_template , AUTO_SCALING_GROUP_NAME )
215
+ update_launch_template (lt_image_id , launch_template )
189
216
else :
190
217
logger .info ('Launch Template "%s" for Auto Scaling Group "%s" is already up to date' ,
191
- launch_template_name , AUTO_SCALING_GROUP_NAME )
218
+ launch_template , AUTO_SCALING_GROUP_NAME )
192
219
193
220
if not all_templates_up_to_date :
194
221
start_instance_refresh ()
0 commit comments