2 '''Hosting Cloudformation Library''' 11 STACK_TEMPLATE_DIR =
'/cloudformation' 12 STACK_TEMPLATE = os.path.join(STACK_TEMPLATE_DIR,
'odyssey.cf.json')
13 LOG = logging.getLogger(__name__)
16 def __get_boto_client__(region):
17 return boto3.client(
'cloudformation', region_name=region)
20 def __get_stack_name__(cluster, region, name, uuid):
21 return '-'.join((cluster, region,
'odyssey', name, uuid))
24 def __get_changeset_name__(stack_name, git_sha):
25 return '-'.join((stack_name, git_sha))
28 def __read_template_body_as_json__():
29 with open(STACK_TEMPLATE,
'r')
as fh:
30 return json.loads(fh.read())
33 def __aws_tags_translation__(tags):
34 return list({
'Key': k,
'Value': v}
for k, v
in tags.items())
37 def __aws_params_translation__(params):
38 return list({
'ParameterKey': k,
39 'ParameterValue': v}
for k, v
in params.items())
42 def __update_template_tasks_environments__(template, env):
50 task_def = template[
'Resources'][task][
'Properties']
51 cdefs = task_def[
'ContainerDefinitions']
53 cenv = dict((x[
'Name'], x[
'Value'])
for x
in cdef[
'Environment'])
55 cdef[
'Environment'] = [{
58 }
for key, value
in cenv.items()]
62 def __validate_template__(client, template_body):
63 return client.validate_template(
64 TemplateBody=template_body
68 def describe_stack(stack, **kwargs):
70 stack_name = __get_stack_name__(stack.cluster,
74 client = __get_boto_client__(stack.region)
75 stack = client.describe_stacks(
77 return stack[
'Stacks'][-1]
80 def describe_changeset(stack, git_sha, **kwargs):
82 stack_name = __get_stack_name__(stack.cluster,
86 changeset_name = __get_changeset_name__(stack_name, git_sha)
87 client = __get_boto_client__(stack.region)
88 changeset = client.describe_change_set(
89 ChangeSetName=changeset_name,
95 def watch_stack_progress(stack, **kwargs):
98 cfn_stack = describe_stack(stack, **kwargs)
99 if cfn_stack[
'StackStatus'].endswith(
'_IN_PROGRESS'):
101 print(
'.', file=sys.stderr, end=
'')
104 print(
'', file=sys.stderr)
106 except Exception
as ex:
107 if kwargs.get(
'verbose',
False):
112 def watch_changeset_progress(stack, git_sha, **kwargs):
114 changeset = describe_changeset(stack, git_sha, **kwargs)
115 if changeset[
'Status']
in [
'CREATE_PENDING',
'CREATE_IN_PROGRESS']:
116 print(
'.', file=sys.stderr, end=
'')
120 print(
'', file=sys.stderr)
124 def list_stack_events(stack, **kwargs):
126 stack_name = __get_stack_name__(stack.cluster,
130 client = __get_boto_client__(stack.region)
131 events = client.describe_stack_events(
132 StackName=stack_name)
133 return events[
'StackEvents']
140 '''Create AWS Cloudformation Stack''' 143 stack_name = __get_stack_name__(stack.cluster,
147 stack_template = __update_template_tasks_environments__(
148 __read_template_body_as_json__(),
151 template_body = json.dumps(stack_template, indent=4)
153 client = __get_boto_client__(stack.region)
155 if kwargs.get(
'verbose',
False):
156 print(__validate_template__(client, template_body), file=sys.stderr)
158 response = client.create_stack(
159 StackName=stack_name,
160 Parameters=__aws_params_translation__(params),
161 TemplateBody=template_body,
162 Capabilities=[
'CAPABILITY_NAMED_IAM'],
163 Tags=__aws_tags_translation__(tags))
164 return response.get(
'StackId')
172 '''Create AWS Cloudformation Changeset''' 175 client = __get_boto_client__(stack.region)
176 stack_name = __get_stack_name__(stack.cluster,
180 changeset_name = __get_changeset_name__(stack_name, git_sha)
181 stack_template = __update_template_tasks_environments__(
182 __read_template_body_as_json__(),
185 template_body = json.dumps(stack_template, indent=2)
187 if kwargs.get(
'verbose',
False):
188 print(__validate_template__(client, template_body), file=sys.stderr)
191 response = client.create_change_set(
192 StackName=stack_name,
193 ChangeSetName=changeset_name,
194 TemplateBody=template_body,
195 Parameters=__aws_params_translation__(params),
196 Capabilities=[
'CAPABILITY_NAMED_IAM'],
197 Tags=__aws_tags_translation__(tags))
198 except Exception
as ex:
199 print(ex, file=sys.stderr)
202 if kwargs.get(
'verbose',
False):
203 print(response, file=sys.stderr)
205 if response[
'ResponseMetadata'][
'HTTPStatusCode'] != 200:
211 def execute_changeset(stack, git_sha, **kwargs):
214 wait_until_complete = kwargs.get(
'wait_until_complete',
False)
215 stack_name = __get_stack_name__(stack.cluster,
219 changeset_name = __get_changeset_name__(stack_name, git_sha)
220 client = __get_boto_client__(stack.region)
221 client.execute_change_set(
222 StackName=stack_name,
223 ChangeSetName=changeset_name)
224 if wait_until_complete:
225 cfn_stack = watch_stack_progress(stack, **kwargs)
226 if cfn_stack[
'StackStatus'] ==
'UPDATE_COMPLETE':
229 LOG.error(cfn_stack[
'StackStatusReason'])
234 def deploy_changeset(stack, git_sha, params, **kwargs):
235 if kwargs.get(
'verbose',
False):
236 print(
'Creating Changeset...', file=sys.stderr)
242 changeset = watch_changeset_progress(stack, git_sha, **kwargs)
244 if not (create_changeset
or changeset[
'STATUS'] ==
'CREATE_COMPLETE'):
245 raise SystemExit(
"Changeset creation failed")
247 if kwargs.get(
'verbose',
False):
248 print(
'Executing Changeset...', file=sys.stderr)
249 return execute_changeset(stack, git_sha, **kwargs)
255 stack_name = __get_stack_name__(stack.cluster,
259 client = boto3.client(
'cloudformation', region_name=stack.region)
260 client.delete_stack(StackName=stack_name)
261 if kwargs.get(
'wait_until_complete',
False):
262 watch_stack_progress(stack, **kwargs)