CloudyScripts 2.14.63 → 2.14.64

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.
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