1
1
#!/usr/bin/env python
2
-
3
2
"""AWS EC2 instance launcher and controller."""
4
3
5
4
from __future__ import print_function
@@ -21,16 +20,9 @@ class AwsEc2(object):
21
20
"""Class to support controlling AWS EC2 istances."""
22
21
23
22
InstanceStatus = collections .namedtuple ("InstanceStatus" , [
24
- "instance_id" ,
25
- "image_id" ,
26
- "instance_type" ,
27
- "state" ,
28
- "private_ip_address" ,
29
- "public_ip_address" ,
30
- "private_dns_name" ,
31
- "public_dns_name" ,
32
- "tags"
33
- ])
23
+ "instance_id" , "image_id" , "instance_type" , "state" , "private_ip_address" ,
24
+ "public_ip_address" , "private_dns_name" , "public_dns_name" , "tags"
25
+ ])
34
26
35
27
def __init__ (self ):
36
28
try :
@@ -46,8 +38,7 @@ def wait_for_state(instance, state, wait_time_secs=0, show_progress=False):
46
38
"""Wait up to 'wait_time_secs' for instance to be in 'state'.
47
39
Return 0 if 'state' reached, 1 otherwise."""
48
40
if show_progress :
49
- print ("Waiting for instance {} to reach '{}' state" .format (instance , state ),
50
- end = "" ,
41
+ print ("Waiting for instance {} to reach '{}' state" .format (instance , state ), end = "" ,
51
42
file = sys .stdout )
52
43
reached_state = False
53
44
end_time = time .time () + wait_time_secs
@@ -83,8 +74,7 @@ def wait_for_state(instance, state, wait_time_secs=0, show_progress=False):
83
74
def control_instance (self , mode , image_id , wait_time_secs = 0 , show_progress = False ):
84
75
"""Controls an AMI instance. Returns 0 & status information, if successful."""
85
76
if mode not in _MODES :
86
- raise ValueError (
87
- "Invalid mode '{}' specified, choose from {}." .format (mode , _MODES ))
77
+ raise ValueError ("Invalid mode '{}' specified, choose from {}." .format (mode , _MODES ))
88
78
89
79
sys .stdout .flush ()
90
80
instance = self .connection .Instance (image_id )
@@ -112,23 +102,17 @@ def control_instance(self, mode, image_id, wait_time_secs=0, show_progress=False
112
102
113
103
ret = 0
114
104
if wait_time_secs > 0 :
115
- ret = self .wait_for_state (
116
- instance = instance ,
117
- state = state ,
118
- wait_time_secs = wait_time_secs ,
119
- show_progress = show_progress )
105
+ ret = self .wait_for_state (instance = instance , state = state , wait_time_secs = wait_time_secs ,
106
+ show_progress = show_progress )
120
107
try :
121
108
# Always provide status after executing command.
122
109
status = self .InstanceStatus (
123
- getattr (instance , "instance_id" , None ),
124
- getattr (instance , "image_id" , None ),
125
- getattr (instance , "instance_type" , None ),
126
- getattr (instance , "state" , None ),
110
+ getattr (instance , "instance_id" , None ), getattr (instance , "image_id" , None ),
111
+ getattr (instance , "instance_type" , None ), getattr (instance , "state" , None ),
127
112
getattr (instance , "private_ip_address" , None ),
128
113
getattr (instance , "public_ip_address" , None ),
129
114
getattr (instance , "private_dns_name" , None ),
130
- getattr (instance , "public_dns_name" , None ),
131
- getattr (instance , "tags" , None ))
115
+ getattr (instance , "public_dns_name" , None ), getattr (instance , "tags" , None ))
132
116
except botocore .exceptions .ClientError as err :
133
117
return 1 , err .message
134
118
@@ -151,18 +135,9 @@ def tag_instance(self, image_id, tags):
151
135
time .sleep (i + 1 )
152
136
instance .create_tags (Tags = tags )
153
137
154
- def launch_instance (self ,
155
- ami ,
156
- instance_type ,
157
- block_devices = None ,
158
- key_name = None ,
159
- security_group_ids = None ,
160
- security_groups = None ,
161
- subnet_id = None ,
162
- tags = None ,
163
- wait_time_secs = 0 ,
164
- show_progress = False ,
165
- ** kwargs ):
138
+ def launch_instance (self , ami , instance_type , block_devices = None , key_name = None ,
139
+ security_group_ids = None , security_groups = None , subnet_id = None , tags = None ,
140
+ wait_time_secs = 0 , show_progress = False , ** kwargs ):
166
141
"""Launches and tags an AMI instance.
167
142
168
143
Returns the tuple (0, status_information), if successful."""
@@ -187,22 +162,15 @@ def launch_instance(self,
187
162
kwargs ["KeyName" ] = key_name
188
163
189
164
try :
190
- instances = self .connection .create_instances (
191
- ImageId = ami ,
192
- InstanceType = instance_type ,
193
- MaxCount = 1 ,
194
- MinCount = 1 ,
195
- ** kwargs )
165
+ instances = self .connection .create_instances (ImageId = ami , InstanceType = instance_type ,
166
+ MaxCount = 1 , MinCount = 1 , ** kwargs )
196
167
except (botocore .exceptions .ClientError , botocore .exceptions .ParamValidationError ) as err :
197
168
return 1 , err .message
198
169
199
170
instance = instances [0 ]
200
171
if wait_time_secs > 0 :
201
- self .wait_for_state (
202
- instance = instance ,
203
- state = "running" ,
204
- wait_time_secs = wait_time_secs ,
205
- show_progress = show_progress )
172
+ self .wait_for_state (instance = instance , state = "running" , wait_time_secs = wait_time_secs ,
173
+ show_progress = show_progress )
206
174
207
175
self .tag_instance (instance .instance_id , tags )
208
176
@@ -218,93 +186,60 @@ def main():
218
186
control_options = optparse .OptionGroup (parser , "Control options" )
219
187
create_options = optparse .OptionGroup (parser , "Create options" )
220
188
221
- parser .add_option ("--mode" ,
222
- dest = "mode" ,
223
- choices = _MODES ,
224
- default = "status" ,
225
- help = "Operations to perform on an EC2 instance, choose one of"
226
- " '{}', defaults to '%default'." .format (", " .join (_MODES )))
189
+ parser .add_option ("--mode" , dest = "mode" , choices = _MODES , default = "status" ,
190
+ help = ("Operations to perform on an EC2 instance, choose one of"
191
+ " '{}', defaults to '%default'." .format (", " .join (_MODES ))))
227
192
228
- control_options .add_option ("--imageId" ,
229
- dest = "image_id" ,
230
- default = None ,
193
+ control_options .add_option ("--imageId" , dest = "image_id" , default = None ,
231
194
help = "EC2 image_id to perform operation on [REQUIRED for control]." )
232
195
233
- control_options .add_option ("--waitTimeSecs" ,
234
- dest = "wait_time_secs" ,
235
- type = int ,
236
- default = 5 * 60 ,
237
- help = "Time to wait for EC2 instance to reach it's new state,"
238
- " defaults to '%default'." )
196
+ control_options .add_option ("--waitTimeSecs" , dest = "wait_time_secs" , type = int , default = 5 * 60 ,
197
+ help = ("Time to wait for EC2 instance to reach it's new state,"
198
+ " defaults to '%default'." ))
239
199
240
- create_options .add_option ("--ami" ,
241
- dest = "ami" ,
242
- default = None ,
200
+ create_options .add_option ("--ami" , dest = "ami" , default = None ,
243
201
help = "EC2 AMI to launch [REQUIRED for create]." )
244
202
245
- create_options .add_option ("--blockDevice" ,
246
- dest = "block_devices" ,
247
- metavar = "DEVICE-NAME DEVICE-SIZE-GB" ,
248
- action = "append" ,
249
- default = [],
203
+ create_options .add_option ("--blockDevice" , dest = "block_devices" ,
204
+ metavar = "DEVICE-NAME DEVICE-SIZE-GB" , action = "append" , default = [],
250
205
nargs = 2 ,
251
- help = "EBS device name and volume size in GiB."
252
- " More than one device can be attached, by specifying"
253
- " this option more than once."
254
- " The device will be deleted on termination of the instance." )
255
-
256
- create_options .add_option ("--instanceType" ,
257
- dest = "instance_type" ,
258
- default = "t1.micro" ,
206
+ help = ("EBS device name and volume size in GiB."
207
+ " More than one device can be attached, by specifying"
208
+ " this option more than once."
209
+ " The device will be deleted on termination of the instance." ))
210
+
211
+ create_options .add_option ("--instanceType" , dest = "instance_type" , default = "t1.micro" ,
259
212
help = "EC2 instance type to launch, defaults to '%default'." )
260
213
261
- create_options .add_option ("--keyName" ,
262
- dest = "key_name" ,
263
- default = None ,
214
+ create_options .add_option ("--keyName" , dest = "key_name" , default = None ,
264
215
help = "EC2 key name [REQUIRED for create]." )
265
216
266
- create_options .add_option ("--securityGroupIds" ,
267
- dest = "security_group_ids" ,
268
- action = "append" ,
217
+ create_options .add_option ("--securityGroupIds" , dest = "security_group_ids" , action = "append" ,
269
218
default = [],
270
- help = "EC2 security group ids. More than one security group id can be"
271
- " added, by specifying this option more than once." )
219
+ help = ( "EC2 security group ids. More than one security group id can be"
220
+ " added, by specifying this option more than once." ) )
272
221
273
- create_options .add_option ("--securityGroup" ,
274
- dest = "security_groups" ,
275
- action = "append" ,
222
+ create_options .add_option ("--securityGroup" , dest = "security_groups" , action = "append" ,
276
223
default = [],
277
- help = "EC2 security group. More than one security group can be added,"
278
- " by specifying this option more than once." )
224
+ help = ( "EC2 security group. More than one security group can be added,"
225
+ " by specifying this option more than once." ) )
279
226
280
- create_options .add_option ("--subnetId" ,
281
- dest = "subnet_id" ,
282
- default = None ,
227
+ create_options .add_option ("--subnetId" , dest = "subnet_id" , default = None ,
283
228
help = "EC2 subnet id to use in VPC." )
284
229
285
- create_options .add_option ("--tagExpireHours" ,
286
- dest = "tag_expire_hours" ,
287
- type = int ,
288
- default = 2 ,
230
+ create_options .add_option ("--tagExpireHours" , dest = "tag_expire_hours" , type = int , default = 2 ,
289
231
help = "EC2 tag expire time in hours, defaults to '%default'." )
290
232
291
- create_options .add_option ("--tagName" ,
292
- dest = "tag_name" ,
293
- default = "" ,
233
+ create_options .add_option ("--tagName" , dest = "tag_name" , default = "" ,
294
234
help = "EC2 tag and instance name." )
295
235
296
- create_options .add_option ("--tagOwner" ,
297
- dest = "tag_owner" ,
298
- default = "" ,
299
- help = "EC2 tag owner." )
236
+ create_options .add_option ("--tagOwner" , dest = "tag_owner" , default = "" , help = "EC2 tag owner." )
300
237
301
- create_options .add_option ("--extraArgs" ,
302
- dest = "extra_args" ,
303
- metavar = "{key1: value1, key2: value2, ..., keyN: valueN}" ,
304
- default = None ,
305
- help = "EC2 create instance keyword args. The argument is specified as"
306
- " bracketed YAML - i.e. JSON with support for single quoted"
307
- " and unquoted keys. Example, '{DryRun: True}'" )
238
+ create_options .add_option (
239
+ "--extraArgs" , dest = "extra_args" , metavar = "{key1: value1, key2: value2, ..., keyN: valueN}" ,
240
+ default = None , help = ("EC2 create instance keyword args. The argument is specified as"
241
+ " bracketed YAML - i.e. JSON with support for single quoted"
242
+ " and unquoted keys. Example, '{DryRun: True}'" ))
308
243
309
244
parser .add_option_group (control_options )
310
245
parser .add_option_group (create_options )
@@ -331,34 +266,25 @@ def main():
331
266
# The 'expire-on' key is a UTC time.
332
267
expire_dt = datetime .datetime .utcnow () + datetime .timedelta (hours = options .tag_expire_hours )
333
268
tags = [{"Key" : "expire-on" , "Value" : expire_dt .strftime ("%Y-%m-%d %H:%M:%S" )},
334
- {"Key" : "Name" , "Value" : options . tag_name },
335
- {"Key" : "owner" , "Value" : options .tag_owner }]
269
+ {"Key" : "Name" ,
270
+ "Value" : options . tag_name }, {"Key" : "owner" , "Value" : options .tag_owner }]
336
271
337
272
my_kwargs = {}
338
273
if options .extra_args is not None :
339
274
my_kwargs = yaml .safe_load (options .extra_args )
340
275
341
276
(ret_code , instance_status ) = aws_ec2 .launch_instance (
342
- ami = options .ami ,
343
- instance_type = options .instance_type ,
344
- block_devices = block_devices ,
345
- key_name = options .key_name ,
346
- security_group_ids = options .security_group_ids ,
347
- security_groups = options .security_groups ,
348
- subnet_id = options .subnet_id ,
349
- tags = tags ,
350
- wait_time_secs = options .wait_time_secs ,
351
- show_progress = True ,
352
- ** my_kwargs )
277
+ ami = options .ami , instance_type = options .instance_type , block_devices = block_devices ,
278
+ key_name = options .key_name , security_group_ids = options .security_group_ids ,
279
+ security_groups = options .security_groups , subnet_id = options .subnet_id , tags = tags ,
280
+ wait_time_secs = options .wait_time_secs , show_progress = True , ** my_kwargs )
353
281
else :
354
282
if not getattr (options , "image_id" , None ):
355
283
parser .print_help ()
356
284
parser .error ("Missing required control option" )
357
285
358
286
(ret_code , instance_status ) = aws_ec2 .control_instance (
359
- mode = options .mode ,
360
- image_id = options .image_id ,
361
- wait_time_secs = options .wait_time_secs ,
287
+ mode = options .mode , image_id = options .image_id , wait_time_secs = options .wait_time_secs ,
362
288
show_progress = True )
363
289
364
290
print ("Return code: {}, Instance status:" .format (ret_code ))
@@ -370,5 +296,6 @@ def main():
370
296
371
297
sys .exit (ret_code )
372
298
299
+
373
300
if __name__ == "__main__" :
374
301
main ()
0 commit comments