CloudyScripts 0.0.11 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,477 +1,180 @@
1
- require "help/script_execution_state"
2
- require "scripts/ec2/ec2_script"
3
- require "help/remote_command_handler"
4
- #require "help/dm_crypt_helper"
5
- require "AWS"
6
-
7
- class AWS::EC2::Base
8
- def register_image_updated(options)
9
- params = {}
10
- params["Name"] = options[:name].to_s
11
- params["BlockDeviceMapping.1.Ebs.SnapshotId"] = options[:snapshot_id].to_s
12
- params["BlockDeviceMapping.1.DeviceName"] = options[:root_device_name].to_s
13
- params["Description"] = options[:description].to_s
14
- params["KernelId"] = options[:kernel_id].to_s
15
- params["RamdiskId"] = options[:ramdisk_id].to_s
16
- params["Architecture"] = options[:architecture].to_s
17
- params["RootDeviceName"] = options[:root_device_name].to_s
18
- return response_generator(:action => "RegisterImage", :params => params)
19
- end
20
- end
21
-
22
- # Creates a bootable EBS storage from an existing AMI.
23
- #
24
-
25
- class Ami2EbsConversion < Ec2Script
26
- # Input parameters
27
- # * aws_access_key => the Amazon AWS Access Key (see Your Account -> Security Credentials)
28
- # * aws_secret_key => the Amazon AWS Secret Key
29
- # * ami_id => the ID of the AMI to be converted
30
- # * security_group_name => name of the security group to start
31
- # * ssh_key_data => Key information for the security group that starts the AMI [if not set, use ssh_key_files]
32
- # * ssh_key_files => Key information for the security group that starts the AMI
33
- # * remote_command_handler => object that allows to connect via ssh and execute commands (optional)
34
- # * ec2_api_handler => object that allows to access the EC2 API (optional)
35
- # * ec2_api_server => server to connect to (option, default is us-east-1.ec2.amazonaws.com)
36
- # * name => the name of the AMI to be created
37
- # * description => description on AMI to be created (optional)
38
- # * temp_device_name => [default /dev/sdj] device name used to attach the temporary storage; change this only if there's already a volume attacged as /dev/sdj (optional, default is /dev/sdj)
39
- # * root_device_name"=> [default /dev/sda1] device name used for the root device (optional)
40
- def initialize(input_params)
41
- super(input_params)
42
- end
43
-
44
- # Executes the script.
45
- def start_script()
46
- begin
47
- # optional parameters and initialization
48
- if @input_params[:name] == nil
49
- @input_params[:name] = "Boot EBS (for AMI #{@input_params[:ami_id]}) at #{Time.now.strftime('%d/%m/%Y %H.%M.%S')}"
50
- else
51
- end
52
- if @input_params[:description] == nil
53
- @input_params[:description] = @input_params[:name]
54
- end
55
- if @input_params[:temp_device_name] == nil
56
- @input_params[:temp_device_name] = "/dev/sdj"
57
- end
58
- if @input_params[:root_device_name] == nil
59
- @input_params[:root_device_name] = "/dev/sda1"
60
- end
61
- @input_params[:script] = self
62
- # start state machine
63
- current_state = Ami2EbsConversionState.load_state(@input_params)
64
- @state_change_listeners.each() {|listener|
65
- current_state.register_state_change_listener(listener)
66
- }
67
- end_state = current_state.start_state_machine()
68
- if end_state.failed?
69
- @result[:failed] = true
70
- @result[:failure_reason] = current_state.end_state.failure_reason
71
- @result[:end_state] = current_state.end_state
72
- else
73
- @result[:failed] = false
74
- end
75
- rescue Exception => e
76
- @logger.warn "exception during encryption: #{e}"
77
- @logger.warn e.backtrace.join("\n")
78
- err = e.to_s
79
- err += " (in #{current_state.end_state.to_s})" unless current_state == nil
80
- @result[:failed] = true
81
- @result[:failure_reason] = err
82
- @result[:end_state] = current_state.end_state unless current_state == nil
83
- ensure
84
- begin
85
- @input_params[:remote_command_handler].disconnect
86
- rescue Exception => e2
87
- end
88
- end
89
- #
90
- @result[:done] = true
91
- end
92
-
93
- # Returns a hash with the following information:
94
- # :done => if execution is done
95
- #
96
- def get_execution_result
97
- @result
98
- end
99
-
100
- private
101
-
102
- # Here begins the state machine implementation
103
- class Ami2EbsConversionState < ScriptExecutionState
104
- def self.load_state(context)
105
- state = context[:initial_state] == nil ? InitialState.new(context) : context[:initial_state]
106
- state
107
- end
108
-
109
- def connect
110
- @context[:script].post_message("connecting to #{@context[:dns_name]}...")
111
- if @context[:remote_command_handler] == nil
112
- @context[:remote_command_handler] = RemoteCommandHandler.new
113
- end
114
- connected = false
115
- remaining_trials = 3
116
- while !connected && remaining_trials > 0
117
- remaining_trials -= 1
118
- if @context[:ssh_keyfile] != nil
119
- begin
120
- @context[:remote_command_handler].connect_with_keyfile(@context[:dns_name], @context[:ssh_keyfile])
121
- connected = true
122
- rescue Exception => e
123
- @logger.info("connection failed due to #{e}")
124
- @logger.debug(e.backtrace.join("\n"))
125
- end
126
- elsif @context[:ssh_keydata] != nil
127
- begin
128
- @context[:remote_command_handler].connect(@context[:dns_name], "root", @context[:ssh_keydata])
129
- connected = true
130
- rescue Exception => e
131
- @logger.info("connection failed due to #{e}")
132
- @logger.debug(e.backtrace.join("\n"))
133
- end
134
- else
135
- raise Exception.new("no key information specified")
136
- end
137
- if !connected
138
- sleep(5) #try again
139
- end
140
- end
141
- if !connected
142
- raise Exception.new("connection attempts stopped")
143
- end
144
- @context[:result][:os] = @context[:remote_command_handler].retrieve_os()
145
- @context[:script].post_message("connected to #{@context[:dns_name]}. OS installed is #{@context[:result][:os]}")
146
- @logger.info "connected to #{@context[:dns_name]}"
147
- end
148
-
149
- end
150
-
151
- # Nothing done yet. Start by instantiating an AMI (in the right zone?)
152
- # which serves to create
153
- class InitialState < Ami2EbsConversionState
154
- def enter
155
- startup_ami()
156
- end
157
-
158
- private
159
-
160
- def startup_ami()
161
- @context[:script].post_message("starting up a new instance for AMI #{@context[:ami_id]}...")
162
- @logger.debug "start up AMI #{@context[:ami_id]}"
163
- res = @context[:ec2_api_handler].run_instances(:image_id => @context[:ami_id],
164
- :security_group => @context[:security_group_name], :key_name => @context[:key_name])
165
- instance_id = res['instancesSet']['item'][0]['instanceId']
166
- @context[:instance_id] = instance_id
167
- @logger.info "started instance #{instance_id}"
168
- @context[:script].post_message("started instance #{instance_id}. wait until it is ready...")
169
- #availability_zone , key_name/group_name
170
- started = false
171
- while started == false
172
- sleep(5)
173
- res = @context[:ec2_api_handler].describe_instances(:instance_id => @context[:instance_id])
174
- state = res['reservationSet']['item'][0]['instancesSet']['item'][0]['instanceState']
175
- @logger.info "instance is in state #{state['name']} (#{state['code']})"
176
- if state['code'].to_i == 16
177
- started = true
178
- @context[:script].post_message("instance is up and running")
179
- @context[:dns_name] = res['reservationSet']['item'][0]['instancesSet']['item'][0]['dnsName']
180
- @context[:availability_zone] = res['reservationSet']['item'][0]['instancesSet']['item'][0]['placement']['availabilityZone']
181
- @context[:kernel_id] = res['reservationSet']['item'][0]['instancesSet']['item'][0]['kernelId']
182
- @context[:ramdisk_id] = res['reservationSet']['item'][0]['instancesSet']['item'][0]['ramdiskId']
183
- @context[:architecture] = res['reservationSet']['item'][0]['instancesSet']['item'][0]['architecture']
184
- elsif state['code'].to_i != 0
185
- @context[:script].post_message("instance in state #{state['name']}")
186
- raise Exception.new('instance failed to start up')
187
- else
188
- @context[:script].post_message("instance still starting up...")
189
- end
190
- end
191
- AmiStarted.new(@context)
192
- end
193
- end
194
-
195
- # Ami started. Create a storage
196
- class AmiStarted < Ami2EbsConversionState
197
- def enter
198
- create_storage()
199
- end
200
-
201
- private
202
-
203
- def create_storage()
204
- @context[:script].post_message("going to create a new EBS volume...")
205
- @logger.debug "create volume in zone #{@context[:availability_zone]}"
206
- res = @context[:ec2_api_handler].create_volume(:availability_zone => @context[:availability_zone], :size => "10")
207
- @context[:volume_id] = res['volumeId']
208
- started = false
209
- while !started
210
- sleep(5)
211
- #TODO: check for timeout?
212
- res = @context[:ec2_api_handler].describe_volumes(:volume_id => @context[:volume_id])
213
- state = res['volumeSet']['item'][0]['status']
214
- @logger.debug "volume state #{state}"
215
- if state == 'available'
216
- started = true
217
- end
218
- end
219
- @context[:script].post_message("EBS volume #{@context[:volume_id]} is ready")
220
- StorageCreated.new(@context)
221
- end
222
-
223
- end
224
-
225
- # Storage created. Attach it.
226
- class StorageCreated < Ami2EbsConversionState
227
- def enter
228
- attach_storage()
229
- end
230
-
231
- private
232
-
233
- def attach_storage()
234
- @context[:script].post_message("going to attach volume #{@context[:volume_id]} to instance #{@context[:instance_id]} on device #{@context[:temp_device_name]}...")
235
- @logger.debug "attach volume #{@context[:volume_id]} to instance #{@context[:instance_id]} on device #{@context[:temp_device_name]}"
236
- @context[:ec2_api_handler].attach_volume(:volume_id => @context[:volume_id],
237
- :instance_id => @context[:instance_id],
238
- :device => @context[:temp_device_name]
239
- )
240
- done = false
241
- while !done
242
- sleep(5)
243
- #TODO: check for timeout?
244
- res = @context[:ec2_api_handler].describe_volumes(:volume_id => @context[:volume_id])
245
- state = res['volumeSet']['item'][0]['status']
246
- @logger.debug "storage attaching: #{state}"
247
- if state == 'in-use'
248
- done = true
249
- end
250
- end
251
- @context[:script].post_message("volume successfully attached")
252
- StorageAttached.new(@context)
253
- end
254
-
255
- end
256
-
257
- # Storage attached. Create a file-system and moun it
258
- class StorageAttached < Ami2EbsConversionState
259
- def enter
260
- create_fs()
261
- end
262
-
263
- private
264
-
265
- def create_fs()
266
- @context[:script].post_message("going to create filesystem on #{@context[:dns_name]} to #{@context[:temp_device_name]}...")
267
- @logger.debug "create filesystem on #{@context[:dns_name]} to #{@context[:temp_device_name]}"
268
- connect()
269
- @context[:remote_command_handler].create_filesystem("ext3", @context[:temp_device_name])
270
- @context[:script].post_message("filesystem system successfully created")
271
- FileSystemCreated.new(@context)
272
- end
273
- end
274
-
275
- # File system created. Mount it.
276
- class FileSystemCreated < Ami2EbsConversionState
277
- def enter
278
- mount_fs()
279
- end
280
-
281
- private
282
-
283
- def mount_fs()
284
- @context[:path] = "/mnt/tmp_#{@context[:volume_id]}"
285
- @context[:script].post_message("going to mount #{@context[:temp_device_name]} on #{@context[:path]}...")
286
- @logger.debug "mount #{@context[:temp_device_name]} on #{@context[:path]}"
287
- @context[:remote_command_handler].mkdir(@context[:path])
288
- @context[:remote_command_handler].mount(@context[:temp_device_name], @context[:path])
289
- sleep(2) #give mount some time
290
- if !@context[:remote_command_handler].drive_mounted?(@context[:path])
291
- raise Exception.new("drive #{@context[:path]} not mounted")
292
- end
293
- @context[:script].post_message("mount successful")
294
- FileSystemMounted.new(@context)
295
- end
296
- end
297
-
298
- # File system created and mounted. Copy the root partition.
299
- class FileSystemMounted < Ami2EbsConversionState
300
- def enter
301
- copy()
302
- end
303
-
304
- private
305
-
306
- def copy()
307
- @context[:script].post_message("going to start copying files to #{@context[:path]}. This may take quite a time...")
308
- @logger.debug "start copying to #{@context[:path]}"
309
- start = Time.new.to_i
310
- @context[:remote_command_handler].rsync("/", "#{@context[:path]}", "/mnt/")
311
- @context[:remote_command_handler].rsync("/dev/", "#{@context[:path]}/dev/")
312
- endtime = Time.new.to_i
313
- @logger.info "copy took #{(endtime-start)}s"
314
- @context[:script].post_message("copying is done (took #{endtime-start})s")
315
- CopyDone.new(@context)
316
- end
317
- end
318
-
319
- # Copy operation done. Unmount volume.
320
- class CopyDone < Ami2EbsConversionState
321
- def enter
322
- unmount()
323
- end
324
-
325
- private
326
-
327
- def unmount()
328
- @context[:script].post_message("going to clean things up. Start with unmounting ...")
329
- @logger.debug "unmount #{@context[:path]}"
330
- @context[:remote_command_handler].umount(@context[:path])
331
- sleep(2) #give umount some time
332
- if @context[:remote_command_handler].drive_mounted?(@context[:path])
333
- raise Exception.new("drive #{@context[:path]} not unmounted")
334
- end
335
- @context[:script].post_message("device unmounted")
336
- VolumeUnmounted.new(@context)
337
- end
338
- end
339
-
340
- # Volume unmounted. Detach it.
341
- class VolumeUnmounted < Ami2EbsConversionState
342
- def enter
343
- detach()
344
- end
345
-
346
- private
347
-
348
- def detach()
349
- @context[:script].post_message("going to detach volume #{@context[:volume_id]}...")
350
- @logger.debug "detach volume #{@context[:volume_id]}"
351
- @context[:ec2_api_handler].detach_volume(:volume_id => @context[:volume_id],
352
- :instance_id => @context[:instance_id]
353
- )
354
- done = false
355
- while !done
356
- sleep(3)
357
- #TODO: check for timeout?
358
- res = @context[:ec2_api_handler].describe_volumes(:volume_id => @context[:volume_id])
359
- @logger.debug "volume detaching: #{res.inspect}"
360
- if res['volumeSet']['item'][0]['status'] == 'available'
361
- done = true
362
- end
363
- end
364
- @context[:script].post_message("volume #{@context[:volume_id]} detached.")
365
- VolumeDetached.new(@context)
366
- end
367
- end
368
-
369
-
370
- # VolumeDetached. Create snaphot
371
- class VolumeDetached < Ami2EbsConversionState
372
- def enter
373
- create_snapshot()
374
- end
375
-
376
- private
377
-
378
- def create_snapshot()
379
- @context[:script].post_message("going to create a snapshot...")
380
- @logger.debug "create snapshot for volume #{@context[:volume_id]}"
381
- res = @context[:ec2_api_handler].create_snapshot(:volume_id => @context[:volume_id])
382
- @context[:snapshot_id] = res['snapshotId']
383
- @logger.info "snapshot_id = #{@context[:snapshot_id]}"
384
- done = false
385
- while !done
386
- sleep(5)
387
- #TODO: check for timeout?
388
- res = @context[:ec2_api_handler].describe_snapshots(:snapshot_id => @context[:snapshot_id])
389
- @logger.debug "snapshot creating: #{res.inspect}"
390
- if res['snapshotSet']['item'][0]['status'] == 'completed'
391
- done = true
392
- end
393
- end
394
- @context[:script].post_message("snapshot is done with ID=#{@context[:snapshot_id]}")
395
- SnapshotCreated.new(@context)
396
- end
397
- end
398
-
399
- # Snapshot created. Delete volume.
400
- class SnapshotCreated < Ami2EbsConversionState
401
- def enter
402
- delete_volume()
403
- end
404
-
405
- private
406
-
407
- def delete_volume
408
- @context[:script].post_message("going to delete volume #{@context[:volume_id]} (no longer needed)...")
409
- @logger.debug "delete volume #{@context[:volume_id]}"
410
- res = @context[:ec2_api_handler].delete_volume(:volume_id => @context[:volume_id])
411
- @context[:script].post_message("volume #{@context[:volume_id]} deleted")
412
- VolumeDeleted.new(@context)
413
- end
414
- end
415
-
416
- # Volume deleted. Register snapshot.
417
- class VolumeDeleted < Ami2EbsConversionState
418
- def enter
419
- register()
420
- end
421
-
422
- private
423
-
424
- def register()
425
- @context[:script].post_message("going to register snapshot #{@context[:snapshot_id]}...")
426
- @logger.debug "register snapshot #{@context[:snapshot_id]} as #{@context[:name]}"
427
- res = @context[:ec2_api_handler].register_image_updated(:snapshot_id => @context[:snapshot_id],
428
- :kernel_id => @context[:kernel_id], :architecture => @context[:architecture],
429
- :root_device_name => @context[:root_device_name],
430
- :description => @context[:description], :name => @context[:name],
431
- :ramdisk_id => @context[:ramdisk_id]
432
- )
433
- @logger.debug "result of registration = #{res.inspect}"
434
- @context[:result][:image_id] = res['imageId']
435
- @logger.info "resulting image_id = #{@context[:result][:image_id]}"
436
- @context[:script].post_message("snapshot #{@context[:snapshot_id]} successfully registered as AMI #{@context[:result][:image_id]} ")
437
- SnapshotRegistered.new(@context)
438
- end
439
- end
440
-
441
- # Snapshot registered. Shutdown instance.
442
- class SnapshotRegistered < Ami2EbsConversionState
443
- def enter
444
- shut_down()
445
- end
446
-
447
- private
448
-
449
- def shut_down()
450
- @context[:script].post_message("going to shut down the temporary instance #{@context[:instance_id]}...")
451
- @logger.debug "shutdown instance #{@context[:instance_id]}"
452
- res = @context[:ec2_api_handler].terminate_instances(:instance_id => @context[:instance_id])
453
- done = false
454
- while done == false
455
- sleep(5)
456
- res = @context[:ec2_api_handler].describe_instances(:instance_id => @context[:instance_id])
457
- state = res['reservationSet']['item'][0]['instancesSet']['item'][0]['instanceState']
458
- @logger.debug "instance in state #{state['name']} (#{state['code']})"
459
- if state['code'].to_i == 48
460
- done = true
461
- elsif state['code'].to_i != 32
462
- raise Exception.new('instance failed to shut down')
463
- end
464
- end
465
- @context[:script].post_message("instance #{@context[:instance_id]} is terminated")
466
- Done.new(@context)
467
- end
468
- end
469
-
470
- # Instance shutdown. Done.
471
- class Done < Ami2EbsConversionState
472
- def done?
473
- true
474
- end
475
- end
476
-
477
- end
1
+ require "help/script_execution_state"
2
+ require "scripts/ec2/ec2_script"
3
+ require "help/remote_command_handler"
4
+ #require "help/dm_crypt_helper"
5
+ require "AWS"
6
+
7
+ class AWS::EC2::Base
8
+ def register_image_updated(options)
9
+ params = {}
10
+ params["Name"] = options[:name].to_s
11
+ params["BlockDeviceMapping.1.Ebs.SnapshotId"] = options[:snapshot_id].to_s
12
+ params["BlockDeviceMapping.1.DeviceName"] = options[:root_device_name].to_s
13
+ params["Description"] = options[:description].to_s
14
+ params["KernelId"] = options[:kernel_id].to_s
15
+ params["RamdiskId"] = options[:ramdisk_id].to_s
16
+ params["Architecture"] = options[:architecture].to_s
17
+ params["RootDeviceName"] = options[:root_device_name].to_s
18
+ return response_generator(:action => "RegisterImage", :params => params)
19
+ end
20
+ end
21
+
22
+ # Creates a bootable EBS storage from an existing AMI.
23
+ #
24
+
25
+ class Ami2EbsConversion < Ec2Script
26
+ # Input parameters
27
+ # * aws_access_key => the Amazon AWS Access Key (see Your Account -> Security Credentials)
28
+ # * aws_secret_key => the Amazon AWS Secret Key
29
+ # * ami_id => the ID of the AMI to be converted
30
+ # * security_group_name => name of the security group to start
31
+ # * ssh_key_data => Key information for the security group that starts the AMI [if not set, use ssh_key_files]
32
+ # * ssh_key_files => Key information for the security group that starts the AMI
33
+ # * remote_command_handler => object that allows to connect via ssh and execute commands (optional)
34
+ # * ec2_api_handler => object that allows to access the EC2 API (optional)
35
+ # * ec2_api_server => server to connect to (option, default is us-east-1.ec2.amazonaws.com)
36
+ # * name => the name of the AMI to be created
37
+ # * description => description on AMI to be created (optional)
38
+ # * temp_device_name => [default /dev/sdj] device name used to attach the temporary storage; change this only if there's already a volume attacged as /dev/sdj (optional, default is /dev/sdj)
39
+ # * root_device_name"=> [default /dev/sda1] device name used for the root device (optional)
40
+ def initialize(input_params)
41
+ super(input_params)
42
+ end
43
+
44
+ def check_input_parameters()
45
+ if @input_params[:name] == nil
46
+ @input_params[:name] = "Boot EBS (for AMI #{@input_params[:ami_id]}) at #{Time.now.strftime('%d/%m/%Y %H.%M.%S')}"
47
+ else
48
+ end
49
+ if @input_params[:description] == nil
50
+ @input_params[:description] = @input_params[:name]
51
+ end
52
+ if @input_params[:temp_device_name] == nil
53
+ @input_params[:temp_device_name] = "/dev/sdj"
54
+ end
55
+ if @input_params[:root_device_name] == nil
56
+ @input_params[:root_device_name] = "/dev/sda1"
57
+ end
58
+ end
59
+
60
+ def load_initial_state()
61
+ Ami2EbsConversionState.load_state(@input_params)
62
+ end
63
+
64
+ private
65
+
66
+ # Here begins the state machine implementation
67
+ class Ami2EbsConversionState < ScriptExecutionState
68
+ def self.load_state(context)
69
+ state = context[:initial_state] == nil ? InitialState.new(context) : context[:initial_state]
70
+ state
71
+ end
72
+
73
+ end
74
+
75
+ # Nothing done yet. Start by instantiating an AMI (in the right zone?)
76
+ # which serves to create
77
+ class InitialState < Ami2EbsConversionState
78
+ def enter
79
+ launch_instance()
80
+ AmiStarted.new(@context)
81
+ end
82
+ end
83
+
84
+ # Ami started. Create a storage
85
+ class AmiStarted < Ami2EbsConversionState
86
+ def enter
87
+ create_volume()
88
+ StorageCreated.new(@context)
89
+ end
90
+ end
91
+
92
+ # Storage created. Attach it.
93
+ class StorageCreated < Ami2EbsConversionState
94
+ def enter
95
+ attach_volume()
96
+ StorageAttached.new(@context)
97
+ end
98
+ end
99
+
100
+ # Storage attached. Create a file-system and moun it
101
+ class StorageAttached < Ami2EbsConversionState
102
+ def enter
103
+ connect()
104
+ create_fs()
105
+ FileSystemCreated.new(@context)
106
+ end
107
+ end
108
+
109
+ # File system created. Mount it.
110
+ class FileSystemCreated < Ami2EbsConversionState
111
+ def enter
112
+ mount_fs()
113
+ FileSystemMounted.new(@context)
114
+ end
115
+ end
116
+
117
+ # File system created and mounted. Copy the root partition.
118
+ class FileSystemMounted < Ami2EbsConversionState
119
+ def enter
120
+ copy()
121
+ CopyDone.new(@context)
122
+ end
123
+ end
124
+
125
+ # Copy operation done. Unmount volume.
126
+ class CopyDone < Ami2EbsConversionState
127
+ def enter
128
+ unmount_fs()
129
+ VolumeUnmounted.new(@context)
130
+ end
131
+ end
132
+
133
+ # Volume unmounted. Detach it.
134
+ class VolumeUnmounted < Ami2EbsConversionState
135
+ def enter
136
+ detach_volume()
137
+ VolumeDetached.new(@context)
138
+ end
139
+ end
140
+
141
+ # VolumeDetached. Create snaphot
142
+ class VolumeDetached < Ami2EbsConversionState
143
+ def enter
144
+ create_snapshot()
145
+ SnapshotCreated.new(@context)
146
+ end
147
+ end
148
+
149
+ # Snapshot created. Delete volume.
150
+ class SnapshotCreated < Ami2EbsConversionState
151
+ def enter
152
+ delete_volume()
153
+ VolumeDeleted.new(@context)
154
+ end
155
+ end
156
+
157
+ # Volume deleted. Register snapshot.
158
+ class VolumeDeleted < Ami2EbsConversionState
159
+ def enter
160
+ register_snapshot()
161
+ SnapshotRegistered.new(@context)
162
+ end
163
+ end
164
+
165
+ # Snapshot registered. Shutdown instance.
166
+ class SnapshotRegistered < Ami2EbsConversionState
167
+ def enter
168
+ shut_down_instance()
169
+ Done.new(@context)
170
+ end
171
+ end
172
+
173
+ # Instance shutdown. Done.
174
+ class Done < Ami2EbsConversionState
175
+ def done?
176
+ true
177
+ end
178
+ end
179
+
180
+ end