2 '''Stack migration definitions 4 The migration definitions are used to defined the specific functions 5 used for migrating stacks between specific versions. 7 The `MIGRATIONS` dictionary contains the mappings between 8 `'%(from)s-%(to)s'` version strings and the specific function to 9 perform the migration. The specific migration functions should be 10 denoted as private to this module. 15 def migrate_083_084(stack, **kwargs):
19 cluster = stack.cluster
20 created = stack.created
21 creator = stack.creator
24 stack.unset(
'region', meta=
True)
25 stack.unset(
'cluster', meta=
True)
26 stack.unset(
'created', meta=
True)
27 stack.unset(
'creator', meta=
True)
28 stack.unset(
'uuid', meta=
True)
29 stack.unset(
'stack_version', meta=
True)
30 stack.unset(
'state', meta=
True)
32 stack.set(
'region', region)
33 stack.set(
'cluster', cluster)
34 stack.set(
'created', created)
35 stack.set(
'creator', creator)
36 stack.set(
'uuid', uuid)
37 stack.set(
'stack_version',
'0.8.4')
38 stack.set(
'state',
'active')
40 stack.unset(
'resources')
43 stack._save(changelog=
'Migrated stack from 0.8.3 to 0.8.4')
44 except Exception
as ex:
45 if kwargs.get(
'verbose',
False):
47 stack.update_state(
'corrupt')
50 def migrate_082_083(stack, **kwargs):
52 from .
import stack
as stk
55 git_sha = os.environ[
'GIT_REV']
57 environment_name =
'homer' 59 stack.set(
'environment_name', environment_name)
61 stk.upgrade_cfn_stack(stack, git_sha, **kwargs)
63 stack.set(
'stack_version',
'0.8.3', meta=
True)
64 stack.update_state(
'active')
65 except Exception
as ex:
66 if kwargs.get(
'verbose',
False):
68 stack.update_state(
'corrupt')
71 def migrate_081_082(stack, **kwargs):
73 from .
import stack
as stk
76 git_sha = os.environ[
'GIT_REV']
78 environment =
'prod' if stack.name ==
'prod' else 'dev' 80 stack.set(
'environment', environment)
82 stk.upgrade_cfn_stack(stack, git_sha, **kwargs)
84 stack.set(
'stack_version',
'0.8.2', meta=
True)
85 stack.update_state(
'active')
86 except Exception
as ex:
87 if kwargs.get(
'verbose',
False):
89 stack.update_state(
'corrupt')
92 def migrate_080_081(stack, **kwargs):
94 from .
import stack
as stk
97 git_sha = os.environ[
'GIT_REV']
99 stk.upgrade_cfn_stack(stack, git_sha, **kwargs)
101 stack.set(
'stack_version',
'0.8.1', meta=
True)
102 stack.update_state(
'active')
103 except Exception
as ex:
104 if kwargs.get(
'verbose',
False):
106 stack.update_state(
'corrupt')
109 def migrate_071_080(stack, **kwargs):
115 from .
import stack
as stk
116 from .
import cloudformation
118 def describe_service(cluster, service, region):
119 client = boto3.client(
'ecs', region_name=region)
120 return client.describe_services(
123 ).get(
'services', [
None])[0]
125 def remove_elb_target_group(region, arn=None):
126 elb_api = boto3.client(
'elbv2', region_name=region)
127 elb_api.delete_target_group(TargetGroupArn=arn)
129 def remove_elb_listener(region, arn=None):
130 elb_api = boto3.client(
'elbv2', region_name=region)
131 elb_api.delete_listener(ListenerArn=arn)
133 def remove_elb(region, arn=None):
134 elb_api = boto3.client(
'elbv2', region_name=region)
135 elb_api.delete_load_balancer(LoadBalancerArn=arn)
137 def remove_ecs_service(region, cluster=None, name=None):
138 ecs_api = boto3.client(
'ecs', region_name=region)
139 ecs_api.update_service(cluster=cluster, service=name, desiredCount=0)
140 ecs_api.delete_service(cluster=cluster, service=name)
142 def remove_task_definition(region, family=None):
143 ecs_api = boto3.client(
'ecs', region_name=region)
144 paginator = ecs_api.get_paginator(
'list_task_definitions')
145 for page
in paginator.paginate(familyPrefix=family, status=
'ACTIVE'):
146 for arn
in page[
'taskDefinitionArns']:
147 print(
"\tDeregistering: %s" % arn)
148 ecs_api.deregister_task_definition(taskDefinition=arn)
150 def remove_dns(region, name=None, record=None, hosted_zone_id=None):
154 'ResourceRecordSet': record
157 r53_api = boto3.client(
'route53')
158 r53_api.change_resource_record_sets(HostedZoneId=hosted_zone_id,
161 def create_cfn_stack(stack, **kwargs):
163 domain =
'.'.join(stack.dns[0].split(
'.')[1:])
164 hostnames = [x.split(
'.')[0]
for x
in stack.dns]
165 app_service = describe_service(
167 'odyssey-%s-app' % stack.name,
169 stack.set(
'app_service_count', app_service[
'desiredCount'])
170 stack.set(
'uuid', str(uuid.uuid4()), meta=
True)
171 stack.set(
'version', stack.name)
173 stk.create_stack_aws_resources(
176 ecs_cluster=stack.cluster,
177 elb_security_group=
'homer-elb-sg',
178 elb_internal_security_group=
'homer-int-elb-sg',
179 eni_security_group=
'homer-ecs-sg',
180 rds_config=
'default',
181 pub_subnet_prefix=
'homer-public',
182 priv_subnet_prefix=
'homer-private',
183 https_cert_hostname=
'*',
186 create_database=
False,
190 def remove_resources(stack):
191 resource_removers = {
193 'elb-target-group': remove_elb_target_group,
194 'elb-listener': remove_elb_listener,
195 'ecs-service': remove_ecs_service,
196 'ecs-task-definition': remove_task_definition,
201 for x
in reversed(stack.resources):
202 print(
'Removing: %s - %s' % (x[
'kind'], x[
'ident']))
204 resource_removers[x[
'kind']](stack.region, **x[
'options'])
205 except Exception
as e:
207 except BaseException
as e:
208 shellish.vtmlprint(
"<red><b>CRITICAL ERROR: %s" % e)
209 stack.update_state(
'corrupt')
213 raise SystemExit(
'Stack not found: %s' % stack.name)
216 create_cfn_stack(stack, **{**kwargs, **{
'IsMigration':
'True'}})
218 cfn_stack = cloudformation.watch_stack_progress(stack, **kwargs)
220 if kwargs.get(
'verbose',
False):
223 if cfn_stack
is None or 'ROLLBACK' in cfn_stack[
'StackStatus']:
224 stack.update_state(
'corrupt')
225 raise SystemExit(
"Unable to create cloudformation resources")
227 remove_resources(stack)
229 git_sha = os.environ[
'GIT_REV']
231 stk.upgrade_cfn_stack(stack, git_sha, **kwargs)
233 stack.set(
'stack_version',
'0.8.0', meta=
True)
234 stack.update_state(
'active')
236 except Exception
as ex:
237 if kwargs.get(
'verbose',
False):
239 stack.update_state(
'corrupt')
243 '0.7.1-0.8.0': migrate_071_080,
244 '0.8.0-0.8.1': migrate_080_081,
245 '0.8.1-0.8.2': migrate_081_082,
246 '0.8.2-0.8.3': migrate_082_083,
247 '0.8.3-0.8.4': migrate_083_084,
252 '''Entry point for stack migration''' 253 migration_str =
'%s-%s' % (from_version, target_version)
254 if migration_str
not in MIGRATIONS:
255 raise SystemExit(
"No migration path found for %s" % migration_str)
257 MIGRATIONS[migration_str](stack, **kwargs)
def migrate_stack(stack, from_version, target_version, **kwargs)