Skip to content

Commit 289d219

Browse files
authored
Merge pull request aws-samples#329 from buzzsurfr/master
Update Automated Cloud9 build to empty bucket
2 parents 4ef27b6 + 266bc21 commit 289d219

File tree

3 files changed

+174
-72
lines changed

3 files changed

+174
-72
lines changed

cloud9-development/readme.adoc

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,6 @@ Delete kubernetes cluster
170170

171171
Wait until all resources are deleted by kops
172172

173-
==== Delete S3 bucket
174-
175-
See the link:https://docs.aws.amazon.com/AmazonS3/latest/user-guide/empty-bucket.html[documentation] to delete S3 bucket using AWS Console
176-
177-
Note: you can get the name of S3 bucket name (KOPS_STATE_STORE) in the Outputs tab in your CloudFormation Console
178-
179173
==== Delete Cloud9
180174

181175
Go to CloudFormation console, right click template with name 'k8s-workshop' and select #Delete Stack

cloud9-development/templates/lab-ide-novpc.template

Lines changed: 88 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@
6060
"arn:aws:iam::aws:policy/AmazonRoute53FullAccess",
6161
"arn:aws:iam::aws:policy/AmazonS3FullAccess",
6262
"arn:aws:iam::aws:policy/IAMFullAccess",
63-
"arn:aws:iam::aws:policy/AmazonVPCFullAccess"
63+
"arn:aws:iam::aws:policy/AmazonVPCFullAccess",
64+
"arn:aws:iam::aws:policy/AWSCloudFormationReadOnlyAccess"
6465
],
6566
"Path": "/"
6667
}
@@ -79,7 +80,10 @@
7980
"AddRoleToInstance": {
8081
"Description": "Add LabIdeRole to Cloud9 IDE Instance",
8182
"Type": "Custom::AddRoleToInstance",
82-
"DependsOn": ["AddRoleToInstanceFunction"],
83+
"DependsOn": [
84+
"AddRoleToInstanceFunction",
85+
"KopsStateStore"
86+
],
8387
"Properties": {
8488
"ServiceToken": {
8589
"Fn::GetAtt": [
@@ -104,6 +108,9 @@
104108
"LabIdeInstanceProfile",
105109
"Arn"
106110
]
111+
},
112+
"BucketName": {
113+
"Ref": "KopsStateStore"
107114
}
108115
}
109116
},
@@ -115,43 +122,65 @@
115122
"Fn::Join": [
116123
"\n",
117124
[
125+
"from __future__ import print_function",
118126
"import boto3",
127+
"import logging",
128+
"import json",
119129
"import time",
120130
"import traceback",
121131
"import cfnresponse",
122132
"",
133+
"logger = logging.getLogger()",
134+
"logger.setLevel(logging.INFO)",
135+
"",
123136
"def handler(event, context):",
137+
" logger.debug('Event: {}'.format(event))",
138+
" logger.debug('Context: {}'.format(context))",
124139
" responseData = {}",
125140
" ",
126-
" # Immediately respond on Delete (no work to be done)",
141+
" # Immediately respond on Delete",
127142
" if event['RequestType'] == 'Delete':",
128-
" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, 'CustomResourcePhysicalID')",
143+
" # Empty Bucket before CloudFormation deletes it",
144+
" session = boto3.Session()",
145+
" s3 = session.resource(service_name='s3')",
146+
" try:",
147+
" bucket = s3.Bucket(event['ResourceProperties']['BucketName'])",
148+
" bucket.object_versions.delete()",
149+
" ",
150+
" logger.info('Bucket '+event['ResourceProperties']['BucketName']+' objects/versions deleted.')",
151+
" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, 'CustomResourcePhysicalID')",
152+
" except Exception as e:",
153+
" logger.error(e, exc_info=True)",
154+
" responseData = {'Error': traceback.format_exc(e)}",
155+
" cfnresponse.send(event, context, cfnresponse.FAILED, responseData, 'CustomResourcePhysicalID')",
129156
" ",
130-
" try:",
131-
" # Open AWS clients",
132-
" ec2 = boto3.client('ec2')",
133-
" ",
134-
" # Get the InstanceId of the Cloud9 IDE",
135-
" instance = ec2.describe_instances(Filters=[{'Name': 'tag:Name','Values': ['aws-cloud9-'+event['ResourceProperties']['StackName']+'-'+event['ResourceProperties']['EnvironmentId']]}])['Reservations'][0]['Instances'][0]",
136-
" ",
137-
" # Create the IamInstanceProfile request object",
138-
" iam_instance_profile = {",
139-
" 'Arn': event['ResourceProperties']['LabIdeInstanceProfileArn'],",
140-
" 'Name': event['ResourceProperties']['LabIdeInstanceProfileName']",
141-
" }",
142-
" ",
143-
" # Wait for Instance to become ready before adding Role",
144-
" instance_state = instance['State']['Name']",
145-
" while instance_state != 'running':",
146-
" time.sleep(5)",
147-
" instance_state = ec2.describe_instances(InstanceIds=[instance['InstanceId']])",
148-
" ec2.associate_iam_instance_profile(IamInstanceProfile=iam_instance_profile, InstanceId=instance['InstanceId'])",
149-
" ",
150-
" responseData = {'Success': 'Role added to instance'+instance['InstanceId']+'.'}",
151-
" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, 'CustomResourcePhysicalID')",
152-
" except Exception as e:",
153-
" responseData = {'Error': traceback.format_exc(e)}",
154-
" cfnresponse.send(event, context, cfnresponse.FAILED, responseData, 'CustomResourcePhysicalID')"
157+
" if event['RequestType'] == 'Create':",
158+
" try:",
159+
" # Open AWS clients",
160+
" ec2 = boto3.client('ec2')",
161+
" ",
162+
" # Get the InstanceId of the Cloud9 IDE",
163+
" instance = ec2.describe_instances(Filters=[{'Name': 'tag:Name','Values': ['aws-cloud9-'+event['ResourceProperties']['StackName']+'-'+event['ResourceProperties']['EnvironmentId']]}])['Reservations'][0]['Instances'][0]",
164+
" ",
165+
" # Create the IamInstanceProfile request object",
166+
" iam_instance_profile = {",
167+
" 'Arn': event['ResourceProperties']['LabIdeInstanceProfileArn'],",
168+
" 'Name': event['ResourceProperties']['LabIdeInstanceProfileName']",
169+
" }",
170+
" ",
171+
" # Wait for Instance to become ready before adding Role",
172+
" instance_state = instance['State']['Name']",
173+
" while instance_state != 'running':",
174+
" time.sleep(5)",
175+
" instance_state = ec2.describe_instances(InstanceIds=[instance['InstanceId']])",
176+
" ec2.associate_iam_instance_profile(IamInstanceProfile=iam_instance_profile, InstanceId=instance['InstanceId'])",
177+
" ",
178+
" responseData = {'Success': 'Role added to instance'+instance['InstanceId']+'.'}",
179+
" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, 'CustomResourcePhysicalID')",
180+
" except Exception as e:",
181+
" logger.error(e, exc_info=True)",
182+
" responseData = {'Error': traceback.format_exc(e)}",
183+
" cfnresponse.send(event, context, cfnresponse.FAILED, responseData, 'CustomResourcePhysicalID')"
155184
]
156185
]
157186
}
@@ -216,6 +245,34 @@
216245
"iam:PassRole"
217246
],
218247
"Resource": "*"
248+
},
249+
{
250+
"Effect": "Allow",
251+
"Action": [
252+
"s3:*"
253+
],
254+
"Resource": [
255+
{
256+
"Fn::GetAtt": [
257+
"KopsStateStore",
258+
"Arn"
259+
]
260+
},
261+
{
262+
"Fn::Join": [
263+
"",
264+
[
265+
{
266+
"Fn::GetAtt": [
267+
"KopsStateStore",
268+
"Arn"
269+
]
270+
},
271+
"/*"
272+
]
273+
]
274+
}
275+
]
219276
}
220277
]
221278
}
@@ -225,7 +282,7 @@
225282
}
226283
},
227284
"Outputs": {
228-
"LabIdeUrl": {
285+
"Cloud9IDE": {
229286
"Value": {
230287
"Fn::Join": [
231288
"",
@@ -237,9 +294,6 @@
237294
]
238295
]
239296
}
240-
},
241-
"KOPSSTATESTORE": {
242-
"Value": { "Ref": "KopsStateStore" }
243-
}
297+
}
244298
}
245299
}

cloud9-development/templates/lab-ide-vpc.template

Lines changed: 86 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,8 @@
270270
"arn:aws:iam::aws:policy/AmazonRoute53FullAccess",
271271
"arn:aws:iam::aws:policy/AmazonS3FullAccess",
272272
"arn:aws:iam::aws:policy/IAMFullAccess",
273-
"arn:aws:iam::aws:policy/AmazonVPCFullAccess"
273+
"arn:aws:iam::aws:policy/AmazonVPCFullAccess",
274+
"arn:aws:iam::aws:policy/AWSCloudFormationReadOnlyAccess"
274275
],
275276
"Path": "/"
276277
}
@@ -289,7 +290,10 @@
289290
"AddRoleToInstance": {
290291
"Description": "Add LabIdeRole to Cloud9 IDE Instance",
291292
"Type": "Custom::AddRoleToInstance",
292-
"DependsOn": ["AddRoleToInstanceFunction"],
293+
"DependsOn": [
294+
"AddRoleToInstanceFunction",
295+
"KopsStateStore"
296+
],
293297
"Properties": {
294298
"ServiceToken": {
295299
"Fn::GetAtt": [
@@ -314,6 +318,9 @@
314318
"LabIdeInstanceProfile",
315319
"Arn"
316320
]
321+
},
322+
"BucketName": {
323+
"Ref": "KopsStateStore"
317324
}
318325
}
319326
},
@@ -325,43 +332,65 @@
325332
"Fn::Join": [
326333
"\n",
327334
[
335+
"from __future__ import print_function",
328336
"import boto3",
337+
"import logging",
338+
"import json",
329339
"import time",
330340
"import traceback",
331341
"import cfnresponse",
332342
"",
343+
"logger = logging.getLogger()",
344+
"logger.setLevel(logging.INFO)",
345+
"",
333346
"def handler(event, context):",
347+
" logger.debug('Event: {}'.format(event))",
348+
" logger.debug('Context: {}'.format(context))",
334349
" responseData = {}",
335350
" ",
336-
" # Immediately respond on Delete (no work to be done)",
351+
" # Immediately respond on Delete",
337352
" if event['RequestType'] == 'Delete':",
338-
" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, 'CustomResourcePhysicalID')",
353+
" # Empty Bucket before CloudFormation deletes it",
354+
" session = boto3.Session()",
355+
" s3 = session.resource(service_name='s3')",
356+
" try:",
357+
" bucket = s3.Bucket(event['ResourceProperties']['BucketName'])",
358+
" bucket.object_versions.delete()",
359+
" ",
360+
" logger.info('Bucket '+event['ResourceProperties']['BucketName']+' objects/versions deleted.')",
361+
" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, 'CustomResourcePhysicalID')",
362+
" except Exception as e:",
363+
" logger.error(e, exc_info=True)",
364+
" responseData = {'Error': traceback.format_exc(e)}",
365+
" cfnresponse.send(event, context, cfnresponse.FAILED, responseData, 'CustomResourcePhysicalID')",
339366
" ",
340-
" try:",
341-
" # Open AWS clients",
342-
" ec2 = boto3.client('ec2')",
343-
" ",
344-
" # Get the InstanceId of the Cloud9 IDE",
345-
" instance = ec2.describe_instances(Filters=[{'Name': 'tag:Name','Values': ['aws-cloud9-'+event['ResourceProperties']['StackName']+'-'+event['ResourceProperties']['EnvironmentId']]}])['Reservations'][0]['Instances'][0]",
346-
" ",
347-
" # Create the IamInstanceProfile request object",
348-
" iam_instance_profile = {",
349-
" 'Arn': event['ResourceProperties']['LabIdeInstanceProfileArn'],",
350-
" 'Name': event['ResourceProperties']['LabIdeInstanceProfileName']",
351-
" }",
352-
" ",
353-
" # Wait for Instance to become ready before adding Role",
354-
" instance_state = instance['State']['Name']",
355-
" while instance_state != 'running':",
356-
" time.sleep(5)",
357-
" instance_state = ec2.describe_instances(InstanceIds=[instance['InstanceId']])",
358-
" ec2.associate_iam_instance_profile(IamInstanceProfile=iam_instance_profile, InstanceId=instance['InstanceId'])",
359-
" ",
360-
" responseData = {'Success': 'Role added to instance'+instance['InstanceId']+'.'}",
361-
" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, 'CustomResourcePhysicalID')",
362-
" except Exception as e:",
363-
" responseData = {'Error': traceback.format_exc(e)}",
364-
" cfnresponse.send(event, context, cfnresponse.FAILED, responseData, 'CustomResourcePhysicalID')"
367+
" if event['RequestType'] == 'Create':",
368+
" try:",
369+
" # Open AWS clients",
370+
" ec2 = boto3.client('ec2')",
371+
" ",
372+
" # Get the InstanceId of the Cloud9 IDE",
373+
" instance = ec2.describe_instances(Filters=[{'Name': 'tag:Name','Values': ['aws-cloud9-'+event['ResourceProperties']['StackName']+'-'+event['ResourceProperties']['EnvironmentId']]}])['Reservations'][0]['Instances'][0]",
374+
" ",
375+
" # Create the IamInstanceProfile request object",
376+
" iam_instance_profile = {",
377+
" 'Arn': event['ResourceProperties']['LabIdeInstanceProfileArn'],",
378+
" 'Name': event['ResourceProperties']['LabIdeInstanceProfileName']",
379+
" }",
380+
" ",
381+
" # Wait for Instance to become ready before adding Role",
382+
" instance_state = instance['State']['Name']",
383+
" while instance_state != 'running':",
384+
" time.sleep(5)",
385+
" instance_state = ec2.describe_instances(InstanceIds=[instance['InstanceId']])",
386+
" ec2.associate_iam_instance_profile(IamInstanceProfile=iam_instance_profile, InstanceId=instance['InstanceId'])",
387+
" ",
388+
" responseData = {'Success': 'Role added to instance'+instance['InstanceId']+'.'}",
389+
" cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, 'CustomResourcePhysicalID')",
390+
" except Exception as e:",
391+
" logger.error(e, exc_info=True)",
392+
" responseData = {'Error': traceback.format_exc(e)}",
393+
" cfnresponse.send(event, context, cfnresponse.FAILED, responseData, 'CustomResourcePhysicalID')"
365394
]
366395
]
367396
}
@@ -426,6 +455,34 @@
426455
"iam:PassRole"
427456
],
428457
"Resource": "*"
458+
},
459+
{
460+
"Effect": "Allow",
461+
"Action": [
462+
"s3:*"
463+
],
464+
"Resource": [
465+
{
466+
"Fn::GetAtt": [
467+
"KopsStateStore",
468+
"Arn"
469+
]
470+
},
471+
{
472+
"Fn::Join": [
473+
"",
474+
[
475+
{
476+
"Fn::GetAtt": [
477+
"KopsStateStore",
478+
"Arn"
479+
]
480+
},
481+
"/*"
482+
]
483+
]
484+
}
485+
]
429486
}
430487
]
431488
}
@@ -447,9 +504,6 @@
447504
]
448505
]
449506
}
450-
},
451-
"KOPSSTATESTORE": {
452-
"Value": { "Ref": "KopsStateStore" }
453507
}
454508
}
455509
}

0 commit comments

Comments
 (0)