CloudyScripts 0.0.14 → 1.4.15
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/help/ec2_helper.rb +37 -0
- data/lib/help/remote_command_handler.rb +28 -2
- data/lib/help/state_transition_helper.rb +70 -23
- data/lib/scripts/ec2/copy_snapshot.rb +188 -0
- data/lib/scripts/ec2/download_snapshot.rb +1 -0
- metadata +6 -5
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ require 'rake/testtask'
|
|
12
12
|
|
13
13
|
spec = Gem::Specification.new do |s|
|
14
14
|
s.name = 'CloudyScripts'
|
15
|
-
s.version = '
|
15
|
+
s.version = '1.4.15'
|
16
16
|
s.has_rdoc = true
|
17
17
|
s.extra_rdoc_files = ['README.rdoc', 'LICENSE']
|
18
18
|
s.summary = 'Scripts to facilitate programming for infrastructure clouds.'
|
data/lib/help/ec2_helper.rb
CHANGED
@@ -59,4 +59,41 @@ class Ec2Helper
|
|
59
59
|
end
|
60
60
|
return vols['volumeSet']['item'][0][prop.to_s]
|
61
61
|
end
|
62
|
+
|
63
|
+
def snapshot_prop(snapshot_id, prop)
|
64
|
+
snaps = @ec2_api.describe_snapshots(:snapshot_id => snapshot_id)
|
65
|
+
begin
|
66
|
+
if snaps['snapshotSet']['item'].size == 0
|
67
|
+
raise Exception.new("snapshot #{snapshot_id} not found")
|
68
|
+
end
|
69
|
+
return snaps['snapshotSet']['item'][0][prop.to_s]
|
70
|
+
rescue
|
71
|
+
raise Exception.new("snapshot #{snapshot_id} not found")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def ami_prop(ami_id, prop)
|
76
|
+
amis = @ec2_api.describe_images(:image_id => ami_id)
|
77
|
+
begin
|
78
|
+
if amis['imagesSet']['item'].size == 0
|
79
|
+
raise Exception.new("image #{ami_id} not found")
|
80
|
+
end
|
81
|
+
return amis['imagesSet']['item'][0][prop.to_s]
|
82
|
+
rescue
|
83
|
+
raise Exception.new("image #{ami_id} not found")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def instance_prop(instance_id, prop)
|
88
|
+
instances = @ec2_api.describe_instances(:instance_id => instance_id)
|
89
|
+
begin
|
90
|
+
if instances['reservationSet']['item'][0]['instancesSet']['item'].size == 0
|
91
|
+
raise Exception.new("instance #{instance_id} not found")
|
92
|
+
end
|
93
|
+
return instances['reservationSet']['item'][0]['instancesSet']['item'][prop.to_s]
|
94
|
+
rescue
|
95
|
+
raise Exception.new("instance #{instance_id} not found")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
62
99
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'net/ssh'
|
3
|
+
require 'net/scp'
|
4
|
+
require 'timeout'
|
3
5
|
|
4
6
|
# Provides methods to be executed via ssh to remote instances.
|
5
7
|
class RemoteCommandHandler
|
@@ -102,14 +104,21 @@ class RemoteCommandHandler
|
|
102
104
|
end
|
103
105
|
|
104
106
|
# Copy directory using options -avHx
|
105
|
-
def
|
107
|
+
def local_rsync(source_path, dest_path, exclude_path = nil)
|
106
108
|
exclude = ""
|
107
109
|
if exclude_path != nil
|
108
110
|
exclude = "--exclude #{exclude_path}"
|
109
111
|
end
|
110
112
|
e = "rsync -avHx #{exclude} #{source_path} #{dest_path}"
|
111
113
|
@logger.debug "going to execute #{e}"
|
112
|
-
remote_exec_helper(e, nil, nil, false)
|
114
|
+
remote_exec_helper(e, nil, nil, false) #TODO: handle output in stderr?
|
115
|
+
end
|
116
|
+
|
117
|
+
# Copy directory via an ssh-tunnel.
|
118
|
+
def remote_rsync(keyfile, source_path, dest_ip, dest_path)
|
119
|
+
e = "rsync -rlpgoDzq -e "+'"'+"ssh -o stricthostkeychecking=no -i #{keyfile}"+'"'+" #{source_path} root@#{dest_ip}:#{dest_path}"
|
120
|
+
@logger.debug "going to execute #{e}"
|
121
|
+
remote_exec_helper(e, nil, nil, false) #TODO: handle output in stderr?
|
113
122
|
end
|
114
123
|
|
115
124
|
# Zip the complete contents of the source path into the destination file.
|
@@ -122,6 +131,15 @@ class RemoteCommandHandler
|
|
122
131
|
end
|
123
132
|
end
|
124
133
|
|
134
|
+
def echo(data, file)
|
135
|
+
exec = "echo #{data} > #{file}"
|
136
|
+
@logger.debug "going to execute #{exec}"
|
137
|
+
remote_execute(exec, nil, true)
|
138
|
+
if !file_exists?(file)
|
139
|
+
raise Exception.new("file #{file} could not be created")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
125
143
|
# Executes the specified #exec_string on a remote session specified.
|
126
144
|
# When #push_data is specified, the data will be used as input for the
|
127
145
|
# command and thus allow to respond in advance to commands that ask the user
|
@@ -168,6 +186,14 @@ class RemoteCommandHandler
|
|
168
186
|
stdout.join()
|
169
187
|
end
|
170
188
|
|
189
|
+
def upload(ip, user, key_data, local_file, destination_file, timeout = 60)
|
190
|
+
Timeout::timeout(timeout) {
|
191
|
+
Net::SCP.start(ip, user, {:key_data => [key_data], :timeout => timeout}) do |scp|
|
192
|
+
scp.upload!(local_file, destination_file)
|
193
|
+
end
|
194
|
+
}
|
195
|
+
end
|
196
|
+
|
171
197
|
private
|
172
198
|
|
173
199
|
# Executes the specified #exec_string on the opened remote session.
|
@@ -1,6 +1,8 @@
|
|
1
|
+
require 'net/scp'
|
2
|
+
|
1
3
|
# Contains methods that are used by the scripts in the state-machines. Since
|
2
4
|
# they are reused by different scripts, they are factored into this module.
|
3
|
-
#
|
5
|
+
#
|
4
6
|
# Note: it is supposed that a hash named @context exists @context[:script]
|
5
7
|
# must be set to a script object to pass information and messages
|
6
8
|
# to listeners.
|
@@ -20,34 +22,39 @@ module StateTransitionHelper
|
|
20
22
|
def connect(dns_name, ssh_keyfile = nil, ssh_keydata = nil)
|
21
23
|
post_message("connecting to #{dns_name}...")
|
22
24
|
connected = false
|
23
|
-
|
25
|
+
last_connection_problem = ""
|
26
|
+
remaining_trials = 5
|
24
27
|
while !connected && remaining_trials > 0
|
25
28
|
remaining_trials -= 1
|
26
29
|
if ssh_keyfile != nil
|
27
30
|
begin
|
31
|
+
@logger.info("connecting using keyfile")
|
28
32
|
remote_handler().connect_with_keyfile(dns_name, ssh_keyfile)
|
29
33
|
connected = true
|
30
34
|
rescue Exception => e
|
31
35
|
@logger.info("connection failed due to #{e}")
|
32
|
-
|
36
|
+
last_connection_problem = "#{e}"
|
37
|
+
@logger.debug(e.backtrace.select(){|line| line.include?("state_transition_helper")}.join("\n"))
|
33
38
|
end
|
34
39
|
elsif ssh_keydata != nil
|
35
40
|
begin
|
41
|
+
@logger.info("connecting using keydata")
|
36
42
|
remote_handler().connect(dns_name, "root", ssh_keydata)
|
37
43
|
connected = true
|
38
44
|
rescue Exception => e
|
39
45
|
@logger.info("connection failed due to #{e}")
|
40
|
-
|
46
|
+
last_connection_problem = "#{e}"
|
47
|
+
@logger.debug(e.backtrace.select(){|line| line.include?("state_transition_helper")}.join("\n"))
|
41
48
|
end
|
42
49
|
else
|
43
50
|
raise Exception.new("no key information specified")
|
44
51
|
end
|
45
52
|
if !connected
|
46
|
-
sleep(
|
53
|
+
sleep(20) #try again
|
47
54
|
end
|
48
55
|
end
|
49
56
|
if !connected
|
50
|
-
raise Exception.new("connection attempts stopped")
|
57
|
+
raise Exception.new("connection attempts stopped (#{last_connection_problem})")
|
51
58
|
end
|
52
59
|
os = remote_handler().retrieve_os()
|
53
60
|
post_message("connected to #{dns_name}. OS installed is #{os}")
|
@@ -55,6 +62,15 @@ module StateTransitionHelper
|
|
55
62
|
return os
|
56
63
|
end
|
57
64
|
|
65
|
+
# If a remote command handler is connected, disconnect him silently.
|
66
|
+
def disconnect
|
67
|
+
begin
|
68
|
+
remote_handler().disconnect()
|
69
|
+
rescue
|
70
|
+
end
|
71
|
+
self.remote_handler= nil
|
72
|
+
end
|
73
|
+
|
58
74
|
# Launch an instance based on an AMI ID
|
59
75
|
# Input Parameters:
|
60
76
|
# * ami_id => ID of the AMI to be launched
|
@@ -67,11 +83,12 @@ module StateTransitionHelper
|
|
67
83
|
# * kernel_id => EC2 Kernel ID of the started instance
|
68
84
|
# * ramdisk_id => EC2 Ramdisk ID of the started instance
|
69
85
|
# * architecture => architecture (e.g. 386i, 64x) of the started instance
|
70
|
-
def launch_instance(ami_id, key_name, security_group_name)
|
86
|
+
def launch_instance(ami_id, key_name, security_group_name, ec2_handler = nil)
|
87
|
+
ec2_handler = ec2_handler() if ec2_handler == nil
|
71
88
|
post_message("starting up instance to execute the script (AMI = #{ami_id}) ...")
|
72
89
|
@logger.debug "start up AMI #{ami_id}"
|
73
90
|
# find out the image architecture first
|
74
|
-
image_props = ec2_handler
|
91
|
+
image_props = ec2_handler.describe_images(:image_id => ami_id)
|
75
92
|
architecture = image_props['imagesSet']['item'][0]['architecture']
|
76
93
|
instance_type = "m1.small"
|
77
94
|
if architecture != "i386"
|
@@ -81,7 +98,7 @@ module StateTransitionHelper
|
|
81
98
|
@logger.info arch_log_msg
|
82
99
|
post_message(arch_log_msg)
|
83
100
|
# now start it
|
84
|
-
res = ec2_handler
|
101
|
+
res = ec2_handler.run_instances(:image_id => ami_id,
|
85
102
|
:security_group => security_group_name, :key_name => key_name,
|
86
103
|
:instance_type => instance_type
|
87
104
|
)
|
@@ -92,7 +109,7 @@ module StateTransitionHelper
|
|
92
109
|
started = false
|
93
110
|
while started == false
|
94
111
|
sleep(5)
|
95
|
-
res = ec2_handler
|
112
|
+
res = ec2_handler.describe_instances(:instance_id => instance_id)
|
96
113
|
state = res['reservationSet']['item'][0]['instancesSet']['item'][0]['instanceState']
|
97
114
|
@logger.info "instance is in state #{state['name']} (#{state['code']})"
|
98
115
|
if state['code'].to_i == 16
|
@@ -252,10 +269,11 @@ module StateTransitionHelper
|
|
252
269
|
# * volume_id => EC2 ID for the EBS volume to be snapshotted
|
253
270
|
# Returns:
|
254
271
|
# * snapshot_id => EC2 ID for the snapshot created
|
255
|
-
def create_snapshot(volume_id)
|
272
|
+
def create_snapshot(volume_id, description = "")
|
256
273
|
post_message("going to create a snapshot for volume #{volume_id}...")
|
257
274
|
@logger.debug "create snapshot for volume #{volume_id}"
|
258
|
-
res = ec2_handler().create_snapshot(:volume_id => volume_id
|
275
|
+
res = ec2_handler().create_snapshot(:volume_id => volume_id,
|
276
|
+
:description => description)
|
259
277
|
snapshot_id = res['snapshotId']
|
260
278
|
@logger.info "snapshot_id = #{snapshot_id}"
|
261
279
|
done = false
|
@@ -358,8 +376,8 @@ module StateTransitionHelper
|
|
358
376
|
post_message("going to start copying files to #{destination_path}. This may take quite a time...")
|
359
377
|
@logger.debug "start copying to #{destination_path}"
|
360
378
|
start = Time.new.to_i
|
361
|
-
remote_handler().
|
362
|
-
remote_handler().
|
379
|
+
remote_handler().local_rsync("/", "#{destination_path}", "#{destination_path}")
|
380
|
+
remote_handler().local_rsync("/dev/", "#{destination_path}/dev/")
|
363
381
|
endtime = Time.new.to_i
|
364
382
|
@logger.info "copy took #{(endtime-start)}s"
|
365
383
|
post_message("copying is done (took #{endtime-start})s")
|
@@ -376,23 +394,52 @@ module StateTransitionHelper
|
|
376
394
|
post_message("EBS volume successfully zipped")
|
377
395
|
end
|
378
396
|
|
379
|
-
|
397
|
+
def remote_copy(keyname, source_dir, dest_machine, dest_dir)
|
398
|
+
post_message("going to remote copy all files from volume. This may take some time...")
|
399
|
+
remote_handler().remote_rsync("/root/.ssh/#{keyname}.pem", source_dir, dest_machine, dest_dir)
|
400
|
+
post_message("remote copy operation done")
|
401
|
+
end
|
380
402
|
|
381
|
-
def
|
382
|
-
|
383
|
-
|
384
|
-
end
|
403
|
+
def upload_file(ip, user, key_data, file, target_file)
|
404
|
+
post_message("going to upload #{file} to #{ip}:/#{target_file}")
|
405
|
+
remote_handler().upload(ip, user, key_data, file, target_file)
|
385
406
|
end
|
386
407
|
|
408
|
+
#setting/retrieving handlers
|
409
|
+
|
387
410
|
def remote_handler()
|
388
|
-
if @
|
389
|
-
@context[:remote_command_handler]
|
411
|
+
if @remote_handler == nil
|
412
|
+
if @context[:remote_command_handler] == nil
|
413
|
+
@context[:remote_command_handler] = RemoteCommandHandler.new
|
414
|
+
else
|
415
|
+
@remote_handler = @context[:remote_command_handler]
|
416
|
+
end
|
390
417
|
end
|
391
|
-
@
|
418
|
+
@remote_handler
|
419
|
+
end
|
420
|
+
|
421
|
+
def remote_handler=(remote_handler)
|
422
|
+
@remote_handler = remote_handler
|
392
423
|
end
|
393
424
|
|
394
425
|
def ec2_handler()
|
395
|
-
@
|
426
|
+
if @ec2_handler == nil
|
427
|
+
@ec2_handler = @context[:ec2_api_handler]
|
428
|
+
end
|
429
|
+
@ec2_handler
|
430
|
+
end
|
431
|
+
|
432
|
+
def ec2_handler=(ec2_handler)
|
433
|
+
@ec2_handler = ec2_handler
|
434
|
+
end
|
435
|
+
|
436
|
+
|
437
|
+
protected
|
438
|
+
|
439
|
+
def post_message(msg)
|
440
|
+
if @context[:script] != nil
|
441
|
+
@context[:script].post_message(msg)
|
442
|
+
end
|
396
443
|
end
|
397
444
|
|
398
445
|
end
|
@@ -0,0 +1,188 @@
|
|
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 "help/ec2_helper"
|
6
|
+
require "AWS"
|
7
|
+
|
8
|
+
# Copy a given snapshot to another region
|
9
|
+
# * start up instance in source-region, create volume from snapshot, attach volume, and mount it
|
10
|
+
# * start up instance in destination-region, create empty volume of same size, attache volume, and mount it
|
11
|
+
# * copy the destination key to the source instance
|
12
|
+
# * perform an rsynch
|
13
|
+
# sync -PHAXaz --rsh "ssh -i /home/${src_user}/.ssh/id_${dst_keypair}" --rsync-path "sudo rsync" ${src_dir}/ ${dst_user}@${dst_public_fqdn}:${dst_dir}/
|
14
|
+
# * create a snapshot of the volume
|
15
|
+
# * clean-up everything
|
16
|
+
|
17
|
+
class CopySnapshot< Ec2Script
|
18
|
+
# context information needed
|
19
|
+
# * the EC2 credentials (see #Ec2Script)
|
20
|
+
# * snapshot_id => The ID of the snapshot to be downloaded
|
21
|
+
# * target_ec2_handler => The EC2 handler connected to the region where the snapshot is being copied to
|
22
|
+
# * source_key_name => Key name of the instance that manages the snaphot-volume in the source region
|
23
|
+
# * source_ssh_key_data => Key information for the security group that starts the AMI [if not set, use ssh_key_files]
|
24
|
+
# * source_ssh_key_files => Key information for the security group that starts the AMI
|
25
|
+
# * target_key_name => Key name of the instance that manages the snaphot-volume in the target region
|
26
|
+
# * target_ssh_key_data => Key information for the security group that starts the AMI [if not set, use ssh_key_files]
|
27
|
+
# * target_ssh_key_files => Key information for the security group that starts the AMI
|
28
|
+
# * source_ami_id => ID of the AMI to start in the source region
|
29
|
+
# * target_ami_id => ID of the AMI to start in the target region
|
30
|
+
|
31
|
+
def initialize(input_params)
|
32
|
+
super(input_params)
|
33
|
+
end
|
34
|
+
|
35
|
+
def check_input_parameters()
|
36
|
+
end
|
37
|
+
|
38
|
+
# Load the initial state for the script.
|
39
|
+
# Abstract method to be implemented by extending classes.
|
40
|
+
def load_initial_state()
|
41
|
+
CopySnapshotState.load_state(@input_params)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# Here begins the state machine implementation
|
47
|
+
class CopySnapshotState < ScriptExecutionState
|
48
|
+
|
49
|
+
def self.load_state(context)
|
50
|
+
InitialState.new(context)
|
51
|
+
end
|
52
|
+
|
53
|
+
def local_region
|
54
|
+
self.ec2_handler=(@context[:ec2_api_handler])
|
55
|
+
end
|
56
|
+
|
57
|
+
def remote_region
|
58
|
+
self.ec2_handler=(@context[:target_ec2_handler])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Initial state: start up AMI in source region
|
63
|
+
class InitialState < CopySnapshotState
|
64
|
+
def enter()
|
65
|
+
result = launch_instance(@context[:source_ami_id], @context[:source_key_name], "default")
|
66
|
+
@context[:source_instance_id] = result.first
|
67
|
+
@context[:source_dns_name] = result[1]
|
68
|
+
@context[:source_availability_zone] = result[2]
|
69
|
+
SourceInstanceLaunchedState.new(@context)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Source is started. Create a volume from the snapshot, attach and mount the volume
|
74
|
+
class SourceInstanceLaunchedState < CopySnapshotState
|
75
|
+
def enter()
|
76
|
+
@context[:source_volume_id] = create_volume_from_snapshot(@context[:snapshot_id],
|
77
|
+
@context[:source_availability_zone])
|
78
|
+
device = "/dev/sdj" #TODO: make device configurable
|
79
|
+
mount_point = "/mnt/tmp_#{@context[:source_volume_id]}"
|
80
|
+
attach_volume(@context[:source_volume_id], @context[:source_instance_id], device)
|
81
|
+
connect(@context[:source_dns_name], nil, @context[:source_ssh_keydata])
|
82
|
+
mount_fs(mount_point, device)
|
83
|
+
disconnect()
|
84
|
+
SourceVolumeReadyState.new(@context)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Source is ready. Now start instance in the target region
|
89
|
+
class SourceVolumeReadyState < CopySnapshotState
|
90
|
+
def enter()
|
91
|
+
remote_region()
|
92
|
+
result = launch_instance(@context[:target_ami_id], @context[:target_key_name],
|
93
|
+
"default")
|
94
|
+
@context[:target_instance_id] = result.first
|
95
|
+
@context[:target_dns_name] = result[1]
|
96
|
+
@context[:target_availability_zone] = result[2]
|
97
|
+
TargetInstanceLaunchedState.new(@context)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Destination instance is started. Now configure storage.
|
102
|
+
class TargetInstanceLaunchedState < CopySnapshotState
|
103
|
+
def enter()
|
104
|
+
local_region()
|
105
|
+
ec2_helper = Ec2Helper.new(@context[:ec2_api_handler])
|
106
|
+
volume_size = ec2_helper.snapshot_prop(@context[:snapshot_id], :volumeSize).to_i
|
107
|
+
#
|
108
|
+
remote_region()
|
109
|
+
@context[:target_volume_id] = create_volume(@context[:target_availability_zone], volume_size)
|
110
|
+
device = "/dev/sdj" #TODO: make device configurable
|
111
|
+
mount_point = "/mnt/tmp_#{@context[:target_volume_id]}"
|
112
|
+
attach_volume(@context[:target_volume_id], @context[:target_instance_id], device)
|
113
|
+
connect(@context[:target_dns_name], nil, @context[:target_ssh_keydata])
|
114
|
+
create_fs(@context[:target_dns_name], device)
|
115
|
+
mount_fs(mount_point, device)
|
116
|
+
disconnect()
|
117
|
+
TargetVolumeReadyState.new(@context)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Storages are ready. Only thing missing: the key of the target region
|
122
|
+
# must be available on the instance in the source region to be able to perform
|
123
|
+
# a remote copy.
|
124
|
+
class TargetVolumeReadyState < CopySnapshotState
|
125
|
+
def enter()
|
126
|
+
post_message("upload key of target-instance to source-instance...")
|
127
|
+
upload_file(@context[:source_dns_name], "root", @context[:source_ssh_keydata],
|
128
|
+
@context[:target_ssh_keyfile], "/root/.ssh/#{@context[:target_key_name]}.pem")
|
129
|
+
post_message("credentials are in place to connect source and target.")
|
130
|
+
KeyInPlaceState.new(@context)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Now we can copy.
|
135
|
+
class KeyInPlaceState < CopySnapshotState
|
136
|
+
def enter()
|
137
|
+
connect(@context[:source_dns_name], nil, @context[:source_ssh_keydata])
|
138
|
+
source_dir = "/mnt/tmp_#{@context[:source_volume_id]}/"
|
139
|
+
dest_dir = "/mnt/tmp_#{@context[:target_volume_id]}"
|
140
|
+
remote_copy(@context[:target_key_name], source_dir, @context[:target_dns_name], dest_dir)
|
141
|
+
disconnect()
|
142
|
+
DataCopiedState.new(@context)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Data of snapshot now copied to the new volume. Create a snapshot of the
|
147
|
+
# new volume.
|
148
|
+
class DataCopiedState < CopySnapshotState
|
149
|
+
def enter()
|
150
|
+
remote_region()
|
151
|
+
@context[:new_snapshot_id] = create_snapshot(@context[:target_volume_id], "Created by Cloudy_Scripts - copy_snapshot")
|
152
|
+
@context[:result][:snapshot_id] = @context[:new_snapshot_id]
|
153
|
+
SnapshotCreatedState.new(@context)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Operation done. Now only cleanup is missing, i.e. shut down instances and
|
158
|
+
# remote the volumes that were created. Start with cleaning the ressources
|
159
|
+
# in the local region.
|
160
|
+
class SnapshotCreatedState < CopySnapshotState
|
161
|
+
def enter()
|
162
|
+
local_region()
|
163
|
+
shut_down_instance(@context[:source_instance_id])
|
164
|
+
delete_volume(@context[:source_volume_id])
|
165
|
+
SourceCleanedUpState.new(@context)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Cleanup the resources in the target region.
|
170
|
+
class SourceCleanedUpState < CopySnapshotState
|
171
|
+
def enter()
|
172
|
+
remote_region()
|
173
|
+
shut_down_instance(@context[:target_instance_id])
|
174
|
+
delete_volume(@context[:target_volume_id])
|
175
|
+
Done.new(@context)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
#Cloudy_Script: copy snapshots between regions
|
182
|
+
#start up instance in source-region, create volume from snapshot, attach volume, and mount it
|
183
|
+
#start up instance in destination-region, create empty volume of same size, attache volume, and mount it
|
184
|
+
#copy the destination key to the source instance
|
185
|
+
#perform an rsynch
|
186
|
+
#sync -PHAXaz --rsh "ssh -i /home/${src_user}/.ssh/id_${dst_keypair}" --rsync-path "sudo rsync" ${src_dir}/ ${dst_user}@${dst_public_fqdn}:${dst_dir}/
|
187
|
+
#create a snapshot of the volume
|
188
|
+
#clean-up everything
|
@@ -21,6 +21,7 @@ class DownloadSnapshot < Ec2Script
|
|
21
21
|
# * the EC2 credentials (see #Ec2Script)
|
22
22
|
# * ami_id: the ID of the AMI to be started to perform the operations and to run the web-server for download
|
23
23
|
# * security_group_name => name of the security group used to start the AMI (should open ports for SSH and HTTP)
|
24
|
+
# * key_name => Name of the key to be used to access the instance providing the download
|
24
25
|
# * ssh_key_data => Key information for the security group that starts the AMI [if not set, use ssh_key_files]
|
25
26
|
# * ssh_key_files => Key information for the security group that starts the AMI
|
26
27
|
# * snapshot_id => The ID of the snapshot to be downloaded
|
metadata
CHANGED
@@ -3,10 +3,10 @@ name: CloudyScripts
|
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
|
-
-
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version:
|
6
|
+
- 1
|
7
|
+
- 4
|
8
|
+
- 15
|
9
|
+
version: 1.4.15
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Matthias Jung
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-04-27 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -63,6 +63,7 @@ files:
|
|
63
63
|
- lib/help/state_change_listener.rb
|
64
64
|
- lib/help/state_transition_helper.rb
|
65
65
|
- lib/scripts/ec2/ami2_ebs_conversion.rb
|
66
|
+
- lib/scripts/ec2/copy_snapshot.rb
|
66
67
|
- lib/scripts/ec2/dm_encrypt.rb
|
67
68
|
- lib/scripts/ec2/download_snapshot.rb
|
68
69
|
- lib/scripts/ec2/ec2_script.rb
|