CloudyScripts 2.14.63 → 2.14.64

Sign up to get free protection for your applications and to get access to all the features.
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 = '2.14.63' #<number cloud-stacks supported>.<number cloud-scripts>.<counting releases>
15
+ s.version = '2.14.64' #<number cloud-stacks supported>.<number cloud-scripts>.<counting releases>
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.'
@@ -31,6 +31,8 @@ spec = Gem::Specification.new do |s|
31
31
  s.add_dependency("amazon-ec2")
32
32
  s.add_dependency("net-ssh")
33
33
  s.add_dependency("net-scp")
34
+ s.add_dependency("net-sftp")
35
+ s.add_dependency("zip")
34
36
  end
35
37
 
36
38
  Rake::GemPackageTask.new(spec) do |p|
@@ -579,7 +579,7 @@ module StateTransitionHelper
579
579
  ec2_handler().authorize_security_group_ingress(:group_name => name,
580
580
  :ip_protocol => rule[:ip_protocol], :from_port => rule[:from_port], :to_port => rule[:to_port], :cidr_ip => rule[:cidr_ip])
581
581
  rescue AWS::InvalidPermissionDuplicate => e
582
- @logger.warn "'#{rule[:proto].upcase()} (#{rule[:from_port]}-#{rule[:to_port]})' rule already exists: #{e.to_s}"
582
+ @logger.warn "'#{rule[:ip_protocol].upcase()} (#{rule[:from_port]}-#{rule[:to_port]})' rule already exists: #{e.to_s}"
583
583
  end
584
584
  }
585
585
  end
@@ -626,6 +626,21 @@ module StateTransitionHelper
626
626
  if !type.nil? && !type.empty?
627
627
  fs_type = type
628
628
  end
629
+ #XXX: detect new kernel that have /dev/xvdX device node instead of /dev/sdX
630
+ if device =~ /\/dev\/sd[a-z]/
631
+ if !remote_handler().file_exists?(device)
632
+ post_message("'#{device}' device node not found, checking for new kernel support...")
633
+ @logger.debug "'#{device}' device node not found, checking for new kernel support"
634
+ new_device = device.gsub('sd', 'xvd')
635
+ if remote_handler().file_exists?(new_device)
636
+ post_message("'#{new_device}' device node found")
637
+ @logger.debug "'#{new_device}' device node found"
638
+ device = new_device
639
+ end
640
+ end
641
+ #elsif device =~/\/dev\/xvd[a-z]/
642
+ end
643
+
629
644
  @logger.debug "create '#{fs_type}' filesystem on device '#{device}'"
630
645
  status = remote_handler().create_filesystem(fs_type, device)
631
646
  if status == false
@@ -1334,6 +1349,27 @@ module StateTransitionHelper
1334
1349
  #Ubuntu kernel Amazon Kernel ID
1335
1350
  'aki-87f38cd5' => 'aki-ubuntu-karmic-v2.6.31-302.i386'
1336
1351
  },
1352
+ 'ap-southeast-2' => {'' => 'pv-grub-hd00-V1.01-i386',
1353
+ '' => 'pv-grub-hd00-V1.01-x86_64',
1354
+ '' => 'pv-grub-hd0-V1.01-i386',
1355
+ '' => 'pv-grub-hd0-V1.01-x86_64',
1356
+ '' => 'pv-grub-hd00_1.02-i386',
1357
+ '' => 'pv-grub-hd00_1.02-x86_64',
1358
+ '' => 'pv-grub-hd0_1.02-i386',
1359
+ '' => 'pv-grub-hd0_1.02-x86_64',
1360
+ 'aki-33990e09' => 'pv-grub-hd0_1.03-i386',
1361
+ 'aki-31990e0b' => 'pv-grub-hd0_1.03-x86_64',
1362
+ 'aki-3f990e05' => 'pv-grub-hd00_1.03-i386',
1363
+ 'aki-3d990e07' => 'pv-grub-hd00_1.03-x86_64',
1364
+
1365
+ #RHEL kernel Amazon Kernel ID
1366
+ 'aki-9b8413a1' => 'aki-rhel-i386', # RH-pv-grub-hd0-V1.01-i386
1367
+ 'aki-998413a3' => 'aki-rhel-x86_64', # RH-pv-grub-hd0-V1.01-x86_64
1368
+
1369
+ #Ubuntu kernel Amazon Kernel ID
1370
+ '' => 'aki-ubuntu-karmic-v2.6.31-302.i386'
1371
+ },
1372
+
1337
1373
  'ap-northeast-1' => {'aki-d209a2d3' => 'pv-grub-hd00-V1.01-i386',
1338
1374
  'aki-d409a2d5' => 'pv-grub-hd00-V1.01-x86_64',
1339
1375
  'aki-d609a2d7' => 'pv-grub-hd0-V1.01-i386',
@@ -1358,10 +1394,10 @@ module StateTransitionHelper
1358
1394
  'aki-d03ce3cd' => 'pv-grub-hd00-V1.01-x86_64',
1359
1395
  'aki-863ce39b' => 'pv-grub-hd0-V1.01-i386',
1360
1396
  'aki-d63ce3cb' => 'pv-grub-hd0-V1.01-x86_64',
1361
- 'aki-bc3ce3a1' => 'pv-grub-hd00_1.02-i386',
1362
- 'aki-cc3ce3d1' => 'pv-grub-hd00_1.02-x86_64',
1363
- 'aki-823ce39f' => 'pv-grub-hd0_1.02-i386',
1364
- 'aki-d23ce3cf' => 'pv-grub-hd0_1.02-x86_64',
1397
+ 'aki-823ce39f' => 'pv-grub-hd00_1.02-i386',
1398
+ 'aki-d23ce3cf' => 'pv-grub-hd00_1.02-x86_64',
1399
+ 'aki-bc3ce3a1' => 'pv-grub-hd0_1.02-i386',
1400
+ 'aki-cc3ce3d1' => 'pv-grub-hd0_1.02-x86_64',
1365
1401
  'aki-ca8f51d7' => 'pv-grub-hd0_1.03-i386',
1366
1402
  'aki-c48f51d9' => 'pv-grub-hd0_1.03-x86_64',
1367
1403
  'aki-ce8f51d3' => 'pv-grub-hd00_1.03-i386',
@@ -1407,14 +1443,16 @@ module StateTransitionHelper
1407
1443
  case endpoint
1408
1444
  when /us-east/
1409
1445
  region = "us-east-1"
1410
- when /us-west-2/
1411
- region = "us-west-2"
1412
1446
  when /us-west-1/
1413
1447
  region = "us-west-1"
1448
+ when /us-west-2/
1449
+ region = "us-west-2"
1414
1450
  when /eu-west/
1415
1451
  region = "eu-west-1"
1416
- when /ap-southeast/
1452
+ when /ap-southeast-1/
1417
1453
  region = "ap-southeast-1"
1454
+ when /ap-southeast-2/
1455
+ region = "ap-southeast-2"
1418
1456
  when /ap-northeast/
1419
1457
  region = "ap-northeast-1"
1420
1458
  when /sa-east-1/
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: CloudyScripts
3
3
  version: !ruby/object:Gem::Version
4
- hash: 73
5
- prerelease: false
4
+ hash: 183
5
+ prerelease:
6
6
  segments:
7
7
  - 2
8
8
  - 14
9
- - 63
10
- version: 2.14.63
9
+ - 64
10
+ version: 2.14.64
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matthias Jung
@@ -16,8 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2012-10-16 00:00:00 +00:00
20
- default_executable:
19
+ date: 2013-01-03 00:00:00 Z
21
20
  dependencies:
22
21
  - !ruby/object:Gem::Dependency
23
22
  name: amazon-ec2
@@ -61,6 +60,34 @@ dependencies:
61
60
  version: "0"
62
61
  type: :runtime
63
62
  version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: net-sftp
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :runtime
76
+ version_requirements: *id004
77
+ - !ruby/object:Gem::Dependency
78
+ name: zip
79
+ prerelease: false
80
+ requirement: &id005 !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ type: :runtime
90
+ version_requirements: *id005
64
91
  description: Scripts to facilitate programming for infrastructure clouds.
65
92
  email:
66
93
  - matthias.jung@gmail.com
@@ -255,7 +282,6 @@ files:
255
282
  - lib/scripts/ec2/port_range_detector.rb
256
283
  - lib/scripts/ec2/ec2_script.rb
257
284
  - lib/scripts/ec2/vpc_critical_ports_audit.rb
258
- - lib/scripts/ec2/copy_ami_test.rb
259
285
  - lib/scripts/ec2/copy_snapshot.rb
260
286
  - lib/scripts/ec2/copy_mswindows_ami.rb
261
287
  - lib/scripts/ec2/copy_mswindows_snapshot.rb
@@ -267,7 +293,6 @@ files:
267
293
  - lib/scripts/ec2/snapshot_optimization.rb
268
294
  - lib/scripts/ec2/audit_via_ssh.rb
269
295
  - lib/scripts/ec2/download_snapshot.rb
270
- - lib/scripts/ec2/check_cloudyscripts.rb
271
296
  - lib/scripts/vCloud/v_cloud_script.rb
272
297
  - lib/scripts/vCloud/open_port_checker_vm.rb
273
298
  - lib/cloudyscripts.rb
@@ -281,7 +306,6 @@ files:
281
306
  - lib/help/progress_message_listener.rb
282
307
  - lib/help/remote_command_handler.rb
283
308
  - lib/help/helper.rb
284
- has_rdoc: true
285
309
  homepage: http://elastic-security.com
286
310
  licenses: []
287
311
 
@@ -311,7 +335,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
311
335
  requirements: []
312
336
 
313
337
  rubyforge_project: CloudyScripts
314
- rubygems_version: 1.3.7
338
+ rubygems_version: 1.7.2
315
339
  signing_key:
316
340
  specification_version: 3
317
341
  summary: Scripts to facilitate programming for infrastructure clouds.
@@ -1,142 +0,0 @@
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
- # Goal: check internal piece of CloudyScripts without launching the full scripts
9
- #
10
-
11
- class CheckCloudyScripts < Ec2Script
12
-
13
- def initialize(input_params)
14
- super(input_params)
15
- end
16
-
17
- def check_input_parameters()
18
- if @input_params[:ami_id] == nil && !(@input_params[:ami_id] =~ /^ami-.*$/)
19
- raise Exception.new("Invalid AMI ID specified: #{@input_params[:ami_id]}")
20
- end
21
- ec2_helper = Ec2Helper.new(@input_params[:ec2_api_handler])
22
- if ec2_helper.ami_prop(@input_params[:ami_id], 'rootDeviceType') != "ebs"
23
- raise Exception.new("must be an EBS type image")
24
- end
25
- local_ec2_helper = ec2_helper
26
- if !local_ec2_helper.check_open_port('default', 22)
27
- raise Exception.new("Port 22 must be opened for security group 'default' to connect via SSH in source-region")
28
- end
29
- remote_ec2_helper = Ec2Helper.new(@input_params[:target_ec2_handler])
30
- if !remote_ec2_helper.check_open_port('default', 22)
31
- raise Exception.new("Port 22 must be opened for security group 'default' to connect via SSH in target-region")
32
- end
33
- if @input_params[:root_device_name] == nil
34
- @input_params[:root_device_name] = "/dev/sda1"
35
- end
36
- if @input_params[:temp_device_name] == nil
37
- @input_params[:temp_device_name] = "/dev/sdj"
38
- end
39
- if @input_params[:source_ssh_username] == nil
40
- @input_params[:source_ssh_username] = "root"
41
- end
42
- if @input_params[:target_ssh_username] == nil
43
- @input_params[:target_ssh_username] = "root"
44
- end
45
- end
46
-
47
- # Load the initial state for the script.
48
- # Abstract method to be implemented by extending classes.
49
- def load_initial_state()
50
- CheckCloudyScriptsState.load_state(@input_params)
51
- end
52
-
53
- private
54
-
55
- # Here begins the state machine implementation
56
- class CheckCloudyScriptsState < ScriptExecutionState
57
-
58
- def self.load_state(context)
59
- InitialState.new(context)
60
- end
61
-
62
- def local_region
63
- self.ec2_handler=(@context[:ec2_api_handler])
64
- end
65
-
66
- def remote_region
67
- self.ec2_handler=(@context[:target_ec2_handler])
68
- end
69
- end
70
-
71
- # Initial state: start up AMI in source region
72
- class InitialState < CheckCloudyScriptsState
73
- def enter()
74
- post_message("INFO: Entering InitialState...")
75
-
76
- #@context[:source_instance_id], @context[:source_dns_name], @context[:source_availability_zone],
77
- # @context[:kernel_id], @context[:ramdisk_id], @context[:architecture], @context[:root_device_name] =
78
- # launch_instance(@context[:ami_id], @context[:source_key_name], "default")
79
- start_instance(@context[:source_instance_id])
80
- res = describe_instance(@context[:source_instance_id])
81
- puts "DEBUG: instance: #{res.inspect}"
82
- #@context[:source_instance_id] = "i-0a663643"
83
- @context[:source_dns_name] = res[1]
84
- @context[:source_availability_zone] = res[2]
85
- @context[:kernel_id] = res[3]
86
- @context[:ramdisk_id] = res[4]
87
- @context[:architecture] = res[5]
88
- @context[:root_device_name] = res[6]
89
-
90
- ec2_helper = Ec2Helper.new(@context[:ec2_api_handler])
91
- puts "DEBUG: get_attached returns: #{ec2_helper.get_attached_volumes(@context[:source_instance_id]).inspect}"
92
- @context[:ebs_volume_id] = ec2_helper.get_attached_volumes(@context[:source_instance_id])[0]['volumeId']#TODO: what when more root devices?
93
-
94
- CSTestingState.new(@context)
95
- end
96
- end
97
-
98
- # Snapshot is created from the AMI. Create a volume from the snapshot, attach and mount the volume as second device.
99
- class CSTestingState < CheckCloudyScriptsState
100
- def enter()
101
- post_message("INFO: Entering CSTestingState...")
102
-
103
- #@context[:source_volume_id] = create_volume_from_snapshot(@context[:snapshot_id],
104
- # @context[:source_availability_zone])
105
- @context[:source_volume_id] = "vol-6eb34b06"
106
-
107
- device = @context[:temp_device_name]
108
- mount_point = "/mnt/tmp_#{@context[:source_volume_id]}"
109
- attach_volume(@context[:source_volume_id], @context[:source_instance_id], device)
110
- connect(@context[:source_dns_name], @context[:source_ssh_username], nil, @context[:source_ssh_keydata])
111
- # detect if there is a shift for device mapping (between AWS and the operating system of the system)
112
- root_device_name = get_root_device_name()
113
- # detect letters
114
- aws_root_device = @context[:root_device_name]
115
- aws_letter = aws_root_device.split('/')[2].gsub('sd', '').gsub('xvd', '').gsub(/[0-9]/, '')
116
- os_letter = root_device_name.split('/')[2].gsub('sd', '').gsub('xvd', '').gsub(/[0-9]/, '')
117
- aws_device_letter = device.split('/')[2].gsub('sd', '').gsub('xvd', '').gsub(/[0-9]/, '')
118
- puts "DEBUG: AWS info: #{aws_root_device}, #{aws_letter}"
119
- puts "DEBUG: OS info: #{root_device_name}, #{os_letter}"
120
- if !aws_letter.eql?(os_letter)
121
- post_message("Detected specific kernel with shift between AWS and Kernel OS for device naming")
122
- puts "Detected specific kernel with shift between AWS and Kernel OS for device naming (#{aws_root_device} vs #{root_device_name})"
123
- end
124
- while !aws_letter.eql?(os_letter)
125
- aws_letter.succ!
126
- aws_device_letter.succ!
127
- end
128
- device = "/dev/sd#{aws_device_letter}"
129
- post_message("Using AWS name '#{@context[:temp_device_name]}' and OS name '#{device}'")
130
- puts "Using AWS name '#{@context[:temp_device_name]}' and OS name '#{device}'"
131
- mount_fs(mount_point, device)
132
- # get root partition label and filesystem type
133
- #@context[:label] = get_root_partition_label()
134
- #@context[:fs_type] = get_root_partition_fs_type()
135
- @context[:fs_type], @context[:label] = get_root_partition_fs_type_and_label()
136
- disconnect()
137
-
138
- Done.new()
139
- end
140
- end
141
-
142
- end
@@ -1,449 +0,0 @@
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
- require "help/helper"
8
-
9
-
10
- # Copy a given snapshot to another region
11
- # * start up instance in source-region, create a snapshot from the mounted EBS
12
- # * then create volume from snapshot, attach volume, and mount it
13
- # * start up instance in destination-region, create empty volume of same size, attache volume, and mount it
14
- # * copy the destination key to the source instance
15
- # * perform an rsynch
16
- # 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}/
17
- # * create a snapshot of the volume
18
- # * register the snapshot as AMI
19
- # * clean-up everything
20
-
21
- class CopyAmiTest < Ec2Script
22
- # context information needed
23
- # * the EC2 credentials (see #Ec2Script)
24
- # * ami_id => the ID of the AMI to be copied in another region
25
- # * target_ec2_handler => The EC2 handler connected to the region where the snapshot is being copied to
26
- # * source_ssh_username => The username for ssh for source-instance (default = root)
27
- # * source_key_name => Key name of the instance that manages the snaphot-volume in the source region
28
- # * source_ssh_key_data => Key information for the security group that starts the AMI [if not set, use ssh_key_files]
29
- # * source_ssh_key_files => Key information for the security group that starts the AMI
30
- # * target_ssh_username => The username for ssh for target-instance (default = root)
31
- # * target_key_name => Key name of the instance that manages the snaphot-volume in the target region
32
- # * target_ssh_key_data => Key information for the security group that starts the AMI [if not set, use ssh_key_files]
33
- # * target_ssh_key_files => Key information for the security group that starts the AMI
34
- # * target_ami_id => ID of the AMI to start in the target region
35
- # * name => name of new AMI to be created
36
- # * description => description of new AMI to be created
37
-
38
- def initialize(input_params)
39
- super(input_params)
40
- end
41
-
42
- def check_input_parameters()
43
- post_message("Checking parameters...")
44
- if @input_params[:ami_id] == nil || !(@input_params[:ami_id] =~ /^ami-.*$/)
45
- raise Exception.new("Invalid AMI ID specified: #{@input_params[:ami_id]}")
46
- end
47
- ec2_helper = Ec2Helper.new(@input_params[:ec2_api_handler])
48
- if ec2_helper.ami_prop(@input_params[:ami_id], 'rootDeviceType') != "ebs"
49
- raise Exception.new("must be an EBS type image")
50
- end
51
- local_ec2_helper = ec2_helper
52
- remote_ec2_helper = Ec2Helper.new(@input_params[:target_ec2_handler])
53
- # AWS KeyPair
54
- if @input_params[:source_key_name] == nil || @input_params[:source_key_name].empty?()
55
- raise Exception.new("No KeyPair name specified for source region")
56
- else
57
- begin
58
- local_ec2_helper.check_keypair(@input_params[:source_key_name])
59
- rescue Exception => e
60
- post_message("'#{@input_params[:source_key_name]}' Key pair not found in source region")
61
- raise Exception.new("source region: #{e.to_s}")
62
- end
63
- end
64
- if @input_params[:target_key_name] == nil || @input_params[:target_key_name].empty?()
65
- raise Exception.new("No KeyPair name specified for target region")
66
- else
67
- begin
68
- remote_ec2_helper.check_keypair(@input_params[:target_key_name])
69
- rescue Exception => e
70
- post_message("'#{@input_params[:target_key_name]}' Key pair not found in target region")
71
- raise Exception.new("target region: #{e.to_s}")
72
- end
73
- end
74
- # AWS SecurityGroup
75
- if @input_params[:source_security_group] == nil
76
- @input_params[:source_security_group] = "default"
77
- end
78
- if !local_ec2_helper.check_open_port(@input_params[:source_security_group], 22)
79
- post_message("'#{@input_params[:source_security_group]}' Security Group not opened port 22 for connect via SSH in source region")
80
- @input_params[:source_security_group] = nil
81
- else
82
- post_message("'#{@input_params[:source_security_group]}' Security Group opened port 22 for connect via SSH in source region")
83
- end
84
- if @input_params[:target_security_group] == nil
85
- @input_params[:target_security_group] = "default"
86
- end
87
- if !remote_ec2_helper.check_open_port(@input_params[:target_security_group], 22)
88
- post_message("'#{@input_params[:target_security_group]}' Security Group not opened port 22 for connect via SSH in target region")
89
- @input_params[:target_security_group] = nil
90
- else
91
- post_message("'#{@input_params[:target_security_group]}' Security Group opened port 22 for connect via SSH in target region")
92
- end
93
- # Device to use
94
- if @input_params[:root_device_name] == nil
95
- @input_params[:root_device_name] = "/dev/sda1"
96
- end
97
- if @input_params[:temp_device_name] == nil
98
- @input_params[:temp_device_name] = "/dev/sdj"
99
- end
100
- # SSH Parameters
101
- if @input_params[:source_ssh_username] == nil
102
- @input_params[:source_ssh_username] = "root"
103
- end
104
- if @input_params[:target_ssh_username] == nil
105
- @input_params[:target_ssh_username] = "root"
106
- end
107
- if @input_params[:source_ssh_keydata] == nil
108
- raise Exception.new("No Private Key for source region")
109
- else
110
- begin
111
- check_ssh_key(@input_params[:source_ssh_keydata])
112
- rescue Exception => e
113
- post_message("not a Private Key: #{e.to_s}")
114
- raise Exception.new("Invalid Private Key for source region: #{e.to_s}")
115
- end
116
- end
117
- if @input_params[:target_ssh_keydata] == nil
118
- raise Exception.new("No Private Key for target region")
119
- else
120
- begin
121
- check_ssh_key(@input_params[:target_ssh_keydata])
122
- rescue Exception => e
123
- post_message("not a Private Key: #{e.to_s}")
124
- raise Exception.new("Invalid Private Key for target region: #{e.to_s}")
125
- end
126
- end
127
- # AWS Name and Description
128
- if @input_params[:description] == nil || !check_aws_desc(@input_params[:description])
129
- @input_params[:description] = "Created by CloudyScripts - #{self.class.name}"
130
- end
131
- if @input_params[:name] == nil || !check_aws_name(@input_params[:name])
132
- @input_params[:name] = "Created_by_CloudyScripts/#{self.class.name}_from_#{@input_params[:ami_id]}"
133
- end
134
- end
135
-
136
- # Load the initial state for the script.
137
- # Abstract method to be implemented by extending classes.
138
- def load_initial_state()
139
- CopyAmiTestState.load_state(@input_params)
140
- end
141
-
142
- private
143
-
144
- # Here begins the state machine implementation
145
- class CopyAmiTestState < ScriptExecutionState
146
-
147
- def self.load_state(context)
148
- InitialState.new(context)
149
- end
150
-
151
- def local_region
152
- self.ec2_handler=(@context[:ec2_api_handler])
153
- end
154
-
155
- def remote_region
156
- self.ec2_handler=(@context[:target_ec2_handler])
157
- end
158
- end
159
-
160
- # Initial state: start up AMI in source region
161
- class InitialState < CopyAmiTestState
162
- def enter()
163
- local_region()
164
- #XXX: create a CloudyScripts Security Group with TCP port 22 publicly opened
165
- if @context[:source_security_group] == nil
166
- @context[:source_security_group] = Ec2Script::CS_SEC_GRP_NAME
167
- create_security_group_with_rules(@context[:source_security_group], Ec2Script::CS_SEC_GRP_DESC,
168
- [{:ip_protocol => "tcp", :from_port => 22, :to_port => 22, :cidr_ip => "0.0.0.0/0"}])
169
- post_message("'#{@context[:source_security_group]}' Security Group created with TCP port 22 publicly opened.")
170
- end
171
-
172
- @context[:source_instance_id], @context[:source_dns_name], @context[:source_availability_zone],
173
- @context[:kernel_id], @context[:ramdisk_id], @context[:architecture], @context[:root_device_name] =
174
- launch_instance(@context[:ami_id], @context[:source_key_name], @context[:source_security_group])
175
- ec2_helper = Ec2Helper.new(@context[:ec2_api_handler])
176
- @context[:ebs_volume_id] = ec2_helper.get_attached_volumes(@context[:source_instance_id])[0]['volumeId'] #TODO: what when more root devices?
177
-
178
- SourceInstanceLaunchedState.new(@context)
179
- end
180
- end
181
-
182
- # Source is started. Create a snapshot on the volume that is linked to the instance.
183
- class SourceInstanceLaunchedState < CopyAmiTestState
184
- def enter()
185
- @context[:snapshot_id] = create_snapshot(@context[:ebs_volume_id],
186
- "Created by CloudyScripts - #{self.get_superclass_name()} from #{@context[:ebs_volume_id]}")
187
-
188
- AmiSnapshotCreatedState.new(@context)
189
- end
190
- end
191
-
192
- # Snapshot is created from the AMI. Create a volume from the snapshot, attach and mount the volume as second device.
193
- class AmiSnapshotCreatedState < CopyAmiTestState
194
- def enter()
195
- @context[:source_volume_id] = create_volume_from_snapshot(@context[:snapshot_id],
196
- @context[:source_availability_zone])
197
- device = @context[:temp_device_name]
198
- mount_point = "/mnt/tmp_#{@context[:source_volume_id]}"
199
- #XXX: attach volume after root partition detection
200
- attach_volume(@context[:source_volume_id], @context[:source_instance_id], device)
201
- connect(@context[:source_dns_name], @context[:source_ssh_username], nil, @context[:source_ssh_keydata])
202
- # detect if there is a shift for device mapping (between AWS and the operating system of the system)
203
- root_device_name = get_root_device_name()
204
- # detect letters
205
- aws_root_device = @context[:root_device_name]
206
- aws_letter = aws_root_device.split('/')[2].gsub('sd', '').gsub('xvd', '').gsub(/[0-9]/, '')
207
- os_letter = root_device_name.split('/')[2].gsub('sd', '').gsub('xvd', '').gsub(/[0-9]/, '')
208
- aws_device_letter = device.split('/')[2].gsub('sd', '').gsub('xvd', '').gsub(/[0-9]/, '')
209
- if !aws_letter.eql?(os_letter)
210
- post_message("Detected specific kernel with shift between AWS and Kernel OS for device naming: '#{aws_root_device}' vs '#{root_device_name}'")
211
- end
212
- while !aws_letter.eql?(os_letter)
213
- aws_letter.succ!
214
- aws_device_letter.succ!
215
- end
216
-
217
- # attach volume
218
- #attach_volume(@context[:source_volume_id], @context[:source_instance_id], device)
219
-
220
- device = "/dev/sd#{aws_device_letter}"
221
- # detect root partition vs root volume: simply check if we have several /dev/sdx* entries
222
- parts_count = get_partition_count(device)
223
- if parts_count >= 2
224
- # retrieve partition table, in order to restore it in the target region
225
- post_message("Detected specific volume with a valid partition table on device '#{device}'...")
226
- partition_table = get_partition_table(device)
227
- @context[:partition_table] = partition_table
228
- #XXX: HANDLE at a LOWER LEVEL
229
- # update partition table with device
230
- # s/device/@context[:temp_device_name]/ on partition table
231
- #@context[:partition_table] = partition_table.gsub("#{device}", "#{@context[:temp_device_name]}")
232
- # retrieve the root partition number
233
- os_nb = root_device_name.split('/')[2].gsub('sd', '').gsub('xvd', '').gsub(/[a-z]/, '')
234
- device = device + os_nb
235
- @context[:root_partition_nb] = os_nb
236
- post_message("Using root partition: '#{device}'...")
237
- end
238
- post_message("Using AWS name '#{@context[:temp_device_name]}' and OS name '#{device}'")
239
- mount_fs(mount_point, device)
240
- # get root partition label and filesystem type
241
- #@context[:label] = get_root_partition_label()
242
- #@context[:fs_type] = get_root_partition_fs_type()
243
- @context[:fs_type], @context[:label] = get_root_partition_fs_type_and_label()
244
- disconnect()
245
-
246
- #XXX: go to clean up state
247
- #SourceVolumeReadyState.new(@context)
248
- AmiRegisteredState.new(@context)
249
- end
250
- end
251
-
252
- # Source is ready. Now start instance in the target region
253
- class SourceVolumeReadyState < CopyAmiTestState
254
- def enter()
255
- remote_region()
256
- #XXX: create a CloudyScripts Security Group with TCP port 22 publicly opened
257
- if @context[:target_security_group] == nil
258
- @context[:target_security_group] = Ec2Script::CS_SEC_GRP_NAME
259
- create_security_group_with_rules(@context[:target_security_group], Ec2Script::CS_SEC_GRP_DESC,
260
- [{:ip_protocol => "tcp", :from_port => 22, :to_port => 22, :cidr_ip => "0.0.0.0/0"}])
261
- post_message("'#{@context[:target_security_group]}' Security Group created with TCP port 22 publicly opened.")
262
- end
263
-
264
- result = launch_instance(@context[:target_ami_id], @context[:target_key_name], @context[:target_security_group])
265
- @context[:target_instance_id] = result.first
266
- @context[:target_dns_name] = result[1]
267
- @context[:target_availability_zone] = result[2]
268
-
269
- TargetInstanceLaunchedState.new(@context)
270
- end
271
- end
272
-
273
- # Destination instance is started. Now configure storage.
274
- class TargetInstanceLaunchedState < CopyAmiTestState
275
- def enter()
276
- local_region()
277
- ec2_helper = Ec2Helper.new(@context[:ec2_api_handler])
278
- volume_size = ec2_helper.snapshot_prop(@context[:snapshot_id], :volumeSize).to_i
279
- #
280
- remote_region()
281
- @context[:target_volume_id] = create_volume(@context[:target_availability_zone], volume_size)
282
- device = @context[:temp_device_name]
283
- mount_point = "/mnt/tmp_#{@context[:target_volume_id]}"
284
- attach_volume(@context[:target_volume_id], @context[:target_instance_id], device)
285
- connect(@context[:target_dns_name], @context[:target_ssh_username], nil, @context[:target_ssh_keydata])
286
- # check if we need to create a partition table
287
- if !(@context[:partition_table] == nil)
288
- post_message("Creating a partition table on device '#{device}'...")
289
- set_partition_table(device, @context[:partition_table])
290
- #XXX: HANDLE at a LOWER LEVEL
291
- # before adding partition table, adjust device name
292
- #set_partition_table(device, @context[:partition_table].gsub(/\/dev\/(s|xv)d[a-z]/, "#{@context[:temp_device_name]}"))
293
- # adjust partition to mount
294
- device = device + @context[:root_partition_nb]
295
- end
296
- # make root partition
297
- create_labeled_fs(@context[:target_dns_name], device, @context[:fs_type], @context[:label])
298
- mount_fs(mount_point, device)
299
- disconnect()
300
-
301
- TargetVolumeReadyState.new(@context)
302
- end
303
- end
304
-
305
- # Storages are ready. Only thing missing: the key of the target region
306
- # must be available on the instance in the source region to be able to perform
307
- # a remote copy.
308
- class TargetVolumeReadyState < CopyAmiTestState
309
- def enter()
310
- post_message("upload key of target-instance to source-instance...")
311
- path_candidates = ["/#{@context[:source_ssh_username]}/.ssh/",
312
- "/home/#{@context[:source_ssh_username]}/.ssh/"]
313
- key_path = determine_file(@context[:source_dns_name], @context[:source_ssh_username], @context[:source_ssh_keydata], path_candidates)
314
- #XXX: fix the problem fo key name with white space
315
- #upload_file(@context[:source_dns_name], @context[:source_ssh_username], @context[:source_ssh_keydata],
316
- # @context[:target_ssh_keyfile], "#{key_path}#{@context[:target_key_name]}.pem")
317
- upload_file(@context[:source_dns_name], @context[:source_ssh_username], @context[:source_ssh_keydata],
318
- @context[:target_ssh_keyfile], "#{key_path}#{@context[:target_key_name].gsub(/\s+/, '_')}.pem")
319
- post_message("credentials are in place to connect source and target.")
320
-
321
- KeyInPlaceState.new(@context)
322
- end
323
- end
324
-
325
- # Now we can copy.
326
- class KeyInPlaceState < CopyAmiTestState
327
- def enter()
328
- connect(@context[:target_dns_name], @context[:target_ssh_username], nil, @context[:target_ssh_keydata])
329
- disable_ssh_tty(@context[:target_dns_name])
330
- disconnect()
331
- #
332
- connect(@context[:source_dns_name], @context[:source_ssh_username], nil, @context[:source_ssh_keydata])
333
- source_dir = "/mnt/tmp_#{@context[:source_volume_id]}/"
334
- dest_dir = "/mnt/tmp_#{@context[:target_volume_id]}"
335
- #XXX: fix the problem fo key name with white space
336
- #remote_copy(@context[:source_ssh_username], @context[:target_key_name], source_dir,
337
- # @context[:target_dns_name], @context[:target_ssh_username], dest_dir)
338
- remote_copy(@context[:source_ssh_username], @context[:target_key_name].gsub(/\s+/, '_'), source_dir,
339
- @context[:target_dns_name], @context[:target_ssh_username], dest_dir)
340
- disconnect()
341
- #
342
- connect(@context[:target_dns_name], @context[:target_ssh_username], nil, @context[:target_ssh_keydata])
343
- enable_ssh_tty(@context[:target_dns_name])
344
- unmount_fs(dest_dir)
345
- disconnect()
346
-
347
- DataCopiedState.new(@context)
348
- end
349
- end
350
-
351
- # Data of snapshot now copied to the new volume. Create a snapshot of the
352
- # new volume.
353
- class DataCopiedState < CopyAmiTestState
354
- def enter()
355
- remote_region()
356
- @context[:new_snapshot_id] = create_snapshot(@context[:target_volume_id],
357
- "Created by CloudyScripts - #{self.get_superclass_name()} from #{@context[:target_volume_id]}")
358
-
359
- TargetSnapshotCreatedState.new(@context)
360
- end
361
- end
362
-
363
- # Snapshot Operation done. Now this snapshot must be registered as AMI
364
- class TargetSnapshotCreatedState < CopyAmiTestState
365
- def enter()
366
- remote_region()
367
- # Get Amazon Kernel Image ID
368
- aki = get_aws_kernel_image_aki(@context[:source_availability_zone], @context[:kernel_id],
369
- @context[:target_availability_zone])
370
- device = @context[:root_device_name]
371
- if !(@context[:partition_table] == nil)
372
- device.gsub!(/[0-9]/, '')
373
- post_message("Using BlockDevice for snapshot registration rather than RootDevice '#{device}' due to a valid partition table on device...")
374
- end
375
- @context[:result][:image_id] = register_snapshot(@context[:new_snapshot_id], @context[:name],
376
- device, @context[:description], aki, nil, @context[:architecture])
377
-
378
- AmiRegisteredState.new(@context)
379
- end
380
- end
381
-
382
- # AMI is registered. Now only cleanup is missing, i.e. shut down instances and
383
- # remote the volumes that were created. Start with cleaning the ressources
384
- # in the both regions.
385
- class AmiRegisteredState < CopyAmiTestState
386
- def enter()
387
- post_message("Cleaning Source and Target Regions...")
388
- error = []
389
- local_region()
390
- begin
391
- shut_down_instance(@context[:source_instance_id])
392
- rescue Exception => e
393
- error << e
394
- post_message("Unable to shutdown instance '#{@context[:source_instance_id]}' in source region: #{e.to_s}")
395
- end
396
- begin
397
- delete_volume(@context[:source_volume_id])
398
- rescue Exception => e
399
- error << e
400
- post_message("Unable to delete volume '#{@context[:source_volume_id]}' in source region: #{e.to_s}")
401
- end
402
- begin
403
- delete_snapshot(@context[:snapshot_id])
404
- rescue Exception => e
405
- error << e
406
- post_message("Unable to delete snapshot '#{@context[:snapshot_id]}' in source region: #{e.to_s}")
407
- end
408
- #XXX: delete Security Group according to its name
409
- if @context[:source_security_group].eql?(Ec2Script::CS_SEC_GRP_NAME)
410
- begin
411
- delete_security_group(@context[:source_security_group])
412
- rescue Exception => e
413
- error << e
414
- post_message("Unable to delete Security Group '#{@context[:source_security_group]}' in source region: #{e.to_s}")
415
- end
416
- end
417
- #
418
- remote_region()
419
- begin
420
- shut_down_instance(@context[:target_instance_id])
421
- rescue Exception => e
422
- error << e
423
- post_message("Unable to shutdown instance '#{@context[:target_instance_id]}' in target region: #{e.to_s}")
424
- end
425
- begin
426
- delete_volume(@context[:target_volume_id])
427
- rescue Exception => e
428
- error << e
429
- post_message("Unable to delete volume '#{@context[:target_volume_id]}' in target region: #{e.to_s}")
430
- end
431
- #XXX: delete Security Group according to its name
432
- if @context[:target_security_group].eql?(Ec2Script::CS_SEC_GRP_NAME)
433
- begin
434
- delete_security_group(@context[:target_security_group])
435
- rescue
436
- error << e
437
- post_message("Unable to delete Security Group '#{@context[:target_security_group]}' in target region: #{e.to_s}")
438
- end
439
- end
440
-
441
- if error.size() > 0
442
- raise Exception.new("Cleanup error(s)")
443
- end
444
-
445
- Done.new(@context)
446
- end
447
- end
448
-
449
- end