the-maestro 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/.document +5 -0
  2. data/.gitignore +25 -0
  3. data/LICENSE +23 -0
  4. data/README.rdoc +378 -0
  5. data/Rakefile +116 -0
  6. data/VERSION +1 -0
  7. data/lib/maestro.rb +354 -0
  8. data/lib/maestro/cloud.rb +384 -0
  9. data/lib/maestro/cloud/aws.rb +1231 -0
  10. data/lib/maestro/dsl_property.rb +15 -0
  11. data/lib/maestro/log4r/console_formatter.rb +18 -0
  12. data/lib/maestro/log4r/file_formatter.rb +24 -0
  13. data/lib/maestro/node.rb +123 -0
  14. data/lib/maestro/operating_system.rb +53 -0
  15. data/lib/maestro/operating_system/cent_os.rb +23 -0
  16. data/lib/maestro/operating_system/debian.rb +40 -0
  17. data/lib/maestro/operating_system/fedora.rb +23 -0
  18. data/lib/maestro/operating_system/ubuntu.rb +100 -0
  19. data/lib/maestro/role.rb +36 -0
  20. data/lib/maestro/tasks.rb +52 -0
  21. data/lib/maestro/validator.rb +32 -0
  22. data/rails/init.rb +1 -0
  23. data/test/integration/base_aws.rb +156 -0
  24. data/test/integration/fixtures/config/maestro/cookbooks/emacs/metadata.json +41 -0
  25. data/test/integration/fixtures/config/maestro/cookbooks/emacs/metadata.rb +3 -0
  26. data/test/integration/fixtures/config/maestro/cookbooks/emacs/recipes/default.rb +21 -0
  27. data/test/integration/fixtures/config/maestro/roles/default.json +9 -0
  28. data/test/integration/fixtures/config/maestro/roles/web.json +9 -0
  29. data/test/integration/helper.rb +8 -0
  30. data/test/integration/test_aws_cloud.rb +805 -0
  31. data/test/integration/test_cent_os.rb +104 -0
  32. data/test/integration/test_debian.rb +119 -0
  33. data/test/integration/test_fedora.rb +104 -0
  34. data/test/integration/test_ubuntu.rb +149 -0
  35. data/test/unit/fixtures/invalid-clouds-not-a-directory/config/maestro/clouds +1 -0
  36. data/test/unit/fixtures/invalid-cookbooks-not-a-directory/config/maestro/cookbooks +0 -0
  37. data/test/unit/fixtures/invalid-maestro-not-a-directory/config/maestro +0 -0
  38. data/test/unit/fixtures/invalid-missing-cookbooks/config/maestro/clouds/valid.yml +21 -0
  39. data/test/unit/fixtures/invalid-missing-roles/config/maestro/clouds/valid.yml +21 -0
  40. data/test/unit/fixtures/invalid-roles-not-a-directory/config/maestro/roles +1 -0
  41. data/test/unit/fixtures/ssh/id_rsa-maestro-test-keypair +27 -0
  42. data/test/unit/helper.rb +6 -0
  43. data/test/unit/test_aws_cloud.rb +133 -0
  44. data/test/unit/test_aws_ec2_node.rb +76 -0
  45. data/test/unit/test_aws_elb_node.rb +221 -0
  46. data/test/unit/test_aws_rds_node.rb +380 -0
  47. data/test/unit/test_cent_os.rb +28 -0
  48. data/test/unit/test_cloud.rb +142 -0
  49. data/test/unit/test_debian.rb +62 -0
  50. data/test/unit/test_fedora.rb +28 -0
  51. data/test/unit/test_invalid_mode.rb +11 -0
  52. data/test/unit/test_maestro.rb +140 -0
  53. data/test/unit/test_node.rb +50 -0
  54. data/test/unit/test_operating_system.rb +19 -0
  55. data/test/unit/test_rails_mode.rb +77 -0
  56. data/test/unit/test_role.rb +59 -0
  57. data/test/unit/test_standalone_mode.rb +75 -0
  58. data/test/unit/test_ubuntu.rb +95 -0
  59. data/the-maestro.gemspec +150 -0
  60. metadata +228 -0
@@ -0,0 +1,52 @@
1
+ require "maestro"
2
+
3
+ namespace :maestro do
4
+
5
+ desc "Creates the Maestro config directory structure. If the directories already exist, no action is taken."
6
+ task :create_config_dirs do
7
+ Maestro.create_config_dirs
8
+ end
9
+
10
+ desc "Validates your Maestro configuration files"
11
+ task :validate_configs do
12
+ result = Maestro.validate_configs
13
+ result[1].each {|msg| puts msg}
14
+ end
15
+
16
+ if !Maestro.clouds.nil? && !Maestro.clouds.empty?
17
+ Maestro.clouds.each_pair do |cloud_name, cloud|
18
+ if cloud.valid?
19
+ namespace "#{cloud_name}" do
20
+ desc "Reports the status of the #{cloud_name} cloud"
21
+ task "status" do |t|
22
+ cloud.status
23
+ end
24
+
25
+ desc "Ensures that the #{cloud_name} cloud is running as currently configured"
26
+ task "start" do |t|
27
+ cloud.start
28
+ end
29
+
30
+ desc "Configures the nodes in the #{cloud_name} cloud. This installs Chef and runs your Chef recipes on the node."
31
+ task "configure" do |t|
32
+ cloud.configure
33
+ end
34
+
35
+ desc "Shuts down the #{cloud_name} cloud"
36
+ task "shutdown" do |t|
37
+ cloud.shutdown
38
+ end
39
+
40
+ if cloud.is_a?(Maestro::Cloud::Aws) && !cloud.rds_nodes.empty?
41
+ cloud.rds_nodes.each_pair do |name, node|
42
+ desc "Reboots the #{name} RDS node. Make sure you put up the appropriate maintanance pages first."
43
+ task "reboot-#{name}" do |t|
44
+ cloud.reboot_rds_node(name)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,32 @@
1
+ module Maestro
2
+ # The Validator mixin provides methods for performing validation and reporting validation errors
3
+ module Validator
4
+
5
+ # whether this object is valid or not. defaults to true
6
+ attr :valid
7
+ # the collection of validation error strings. if valid is false, this should contain details as to why the object is invalid
8
+ attr_reader :validation_errors
9
+
10
+ def initialize
11
+ @validation_errors = Array.new
12
+ @valid = true
13
+ end
14
+
15
+ # calls the validate_internal method, which classes including this Module should implement
16
+ def validate
17
+ validate_internal
18
+ end
19
+
20
+ # returns whether this object is valid or not
21
+ def valid?
22
+ @valid
23
+ end
24
+
25
+ # sets this object's valid attribute to false, and records the given
26
+ # validation error string in the validation_errors attribute
27
+ def invalidate(error_str)
28
+ @valid = false
29
+ @validation_errors << error_str
30
+ end
31
+ end
32
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + '/../lib/maestro'
@@ -0,0 +1,156 @@
1
+ require "helper"
2
+ require "etc"
3
+ require "AWS"
4
+ require "aws/s3"
5
+
6
+ # Base AWS contectivity
7
+ module BaseAws
8
+
9
+ #
10
+ # BE CAREFUL!
11
+ #
12
+ # A poorly written test will cost you and others money. The onus is on you to double check
13
+ # that you don't orphan EC2 instances, S3 buckets/objects, Elastic IPs, RDS instances,
14
+ # ELBs, EBS Volumes/Snapshots, etc. The AWS Console is your friend.
15
+ #
16
+ # To be safe, create a new keypair just for use with running these tests. Don't use
17
+ # an existing keypair associated with any sensitive production data!
18
+ #
19
+ # To run the integration tests, place a file named maestro_tests_aws_credentials.rb
20
+ # in your home directory, with the following Hash:
21
+ #
22
+ # {
23
+ # # The name of the keypair to use to authenticate with AWS, start instances, etc
24
+ # :keypair_name => "XXXXXXX-keypair",
25
+ #
26
+ # # Path to the keypair file matching the :keypair_name
27
+ # :keypair_file => "/path/to/your/id_rsa-XXXXXXX-keypair",
28
+ #
29
+ # # Your AWS Account ID
30
+ # :aws_account_id => "XXXX-XXXX-XXXX",
31
+ #
32
+ # # Your AWS Access Key
33
+ # :aws_access_key => "XXXXXXXXXXXXXXXXXXXX",
34
+ #
35
+ # # Your AWS Secret Access Key
36
+ # :aws_secret_access_key => "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
37
+ #
38
+ # # Name of the S3 bucket to store Chef assets in
39
+ # :chef_bucket => "maestro-tests-aws.XXXXXXXX.com"
40
+ # }
41
+ #
42
+ # Make sure you set the appropriate permissions on this file, and delete it when you're done running the integration tests.
43
+ #
44
+
45
+
46
+ #######################
47
+ # Setup
48
+ #######################
49
+ def setup
50
+ @config_file_name = 'maestro_tests_aws_credentials.rb'
51
+ @maestro_aws_credentials = Etc.getpwuid.dir + "/#{@config_file_name}"
52
+ raise "Missing Maestro::Cloud::Aws integration test config file: ~/#{@config_file_name}." if !File.exists?(@maestro_aws_credentials)
53
+ raise "Cannot read Maestro::Cloud::Aws integration test config file: ~/#{@config_file_name}." if !File.readable?(@maestro_aws_credentials)
54
+ @credentials = eval(File.read(@maestro_aws_credentials))
55
+ raise "Invalid Maestro::Cloud::Aws integration test config file: ~/#{@config_file_name}. Does not contain a Hash" if !@credentials.instance_of?(Hash)
56
+ raise "Invalid Maestro::Cloud::Aws integration test config file: ~/#{@config_file_name}. Missing :keypair_name key" if !@credentials.has_key?(:keypair_name)
57
+ raise "Invalid Maestro::Cloud::Aws integration test config file: ~/#{@config_file_name}. Missing :keypair_file key" if !@credentials.has_key?(:keypair_file)
58
+ raise "Invalid Maestro::Cloud::Aws integration test config file: ~/#{@config_file_name}. Missing :aws_account_id key" if !@credentials.has_key?(:aws_account_id)
59
+ raise "Invalid Maestro::Cloud::Aws integration test config file: ~/#{@config_file_name}. Missing :aws_access_key key" if !@credentials.has_key?(:aws_access_key)
60
+ raise "Invalid Maestro::Cloud::Aws integration test config file: ~/#{@config_file_name}. Missing :aws_secret_access_key key" if !@credentials.has_key?(:aws_secret_access_key)
61
+ raise "Invalid Maestro::Cloud::Aws integration test config file: ~/#{@config_file_name}. Missing :chef_bucket key" if !@credentials.has_key?(:chef_bucket)
62
+
63
+ @ec2 = AWS::EC2::Base.new(:access_key_id => @credentials[:aws_access_key], :secret_access_key => @credentials[:aws_secret_access_key], :use_ssl => true)
64
+ @elb = AWS::ELB::Base.new(:access_key_id => @credentials[:aws_access_key], :secret_access_key => @credentials[:aws_secret_access_key], :use_ssl => true)
65
+ @rds = AWS::RDS::Base.new(:access_key_id => @credentials[:aws_access_key], :secret_access_key => @credentials[:aws_secret_access_key], :use_ssl => true)
66
+ AWS::S3::Base.establish_connection!(:access_key_id => @credentials[:aws_access_key], :secret_access_key => @credentials[:aws_secret_access_key], :use_ssl => true)
67
+
68
+ # keep track of the Elastic IPs we started with
69
+ before_addresses = @ec2.describe_addresses()
70
+ @before_elastic_ips = Array.new
71
+ if !before_addresses.addressesSet.nil?
72
+ before_addresses.addressesSet.item.each {|item| @before_elastic_ips << item.publicIp}
73
+ end
74
+
75
+ # keep track of the EBS volumes we started with
76
+ before_volumes = @ec2.describe_volumes()
77
+ @before_volumes = Array.new
78
+ if !before_volumes.volumeSet.nil?
79
+ before_volumes.volumeSet.item.each {|item| @before_volumes << item.volumeId if !item.status.eql? "deleting"}
80
+ end
81
+
82
+ # keep track of the S3 Buckets we started with
83
+ before_buckets = AWS::S3::Service.buckets
84
+ @before_buckets = Array.new
85
+ if !before_buckets.empty?
86
+ before_buckets.each {|bucket| @before_buckets << bucket.name}
87
+ end
88
+ end
89
+
90
+
91
+ #######################
92
+ # Teardown
93
+ #######################
94
+
95
+ def teardown
96
+ # release elastic ips
97
+ after_addresses = @ec2.describe_addresses()
98
+ @after_elastic_ips = Array.new
99
+ if !after_addresses.addressesSet.nil?
100
+ after_addresses.addressesSet.item.each {|item| @after_elastic_ips << item.publicIp}
101
+ end
102
+ @before_elastic_ips.each do |before_elastic_ip|
103
+ found = @after_elastic_ips.find {|after_elastic_ip| after_elastic_ip.eql?(before_elastic_ip)}
104
+ puts "ERROR! AWS integration test error: It appears an Elastic IP address associated with the account before the integration tests ran has been released. This should not happen." if !found
105
+ end
106
+ @after_elastic_ips.each do |after_elastic_ip|
107
+ found = @before_elastic_ips.find {|before_elastic_ip| before_elastic_ip.eql?(after_elastic_ip)}
108
+ if !found
109
+ puts "Releasing AWS integration test Elastic IP: #{after_elastic_ip}"
110
+ @ec2.release_address(:public_ip => after_elastic_ip)
111
+ end
112
+ end
113
+
114
+ # delete EBS volumes
115
+ after_volumes = @ec2.describe_volumes()
116
+ @after_volumes = Array.new
117
+ if !after_volumes.volumeSet.nil?
118
+ after_volumes.volumeSet.item.each {|item| @after_volumes << item.volumeId if !item.status.eql? "deleting"}
119
+ end
120
+ @before_volumes.each do |before_volume|
121
+ found = @after_volumes.find {|after_volume| after_volume.eql?(before_volume)}
122
+ puts "ERROR! AWS Cloud integration test error: It appears an EBS volume associated with the account before the integration tests ran has been deleted. This should not happen." if !found
123
+ end
124
+ @after_volumes.each do |after_volume|
125
+ found = @before_volumes.find {|before_volume| before_volume.eql?(after_volume)}
126
+ if !found
127
+ puts "Deleting AWS integration test EBS Volume: #{after_volume}"
128
+ @ec2.delete_volume(:volume_id => after_volume)
129
+ end
130
+ end
131
+
132
+ # delete S3 buckets
133
+ after_buckets = AWS::S3::Service.buckets
134
+ @after_buckets = Array.new
135
+ if !after_buckets.empty?
136
+ after_buckets.each {|bucket| @after_buckets << bucket.name}
137
+ end
138
+ @before_buckets.each do |before_bucket_name|
139
+ found = @after_buckets.find {|after_bucket_name| after_bucket_name.eql?(before_bucket_name)}
140
+ puts "ERROR! AWS Cloud integration test error: It appears an S3 Bucket belonging to the account before the integration tests ran has been deleted. This should not happen." if !found
141
+ end
142
+ @after_buckets.each do |after_bucket_name|
143
+ found = @before_buckets.find {|before_bucket_name| before_bucket_name.eql?(after_bucket_name)}
144
+ if !found
145
+ puts "Deleting all objects in S3 Bucket: #{after_bucket_name}"
146
+ bucket = AWS::S3::Bucket.find(after_bucket_name)
147
+ bucket.delete_all
148
+ puts "Deleting S3 Bucket: #{after_bucket_name}"
149
+ bucket.delete
150
+ end
151
+ end
152
+
153
+ ENV.delete Maestro::MAESTRO_DIR_ENV_VAR
154
+ end
155
+
156
+ end
@@ -0,0 +1,41 @@
1
+ {
2
+ "dependencies": {
3
+ },
4
+ "replacing": {
5
+ },
6
+ "description": "Installs emacs",
7
+ "groupings": {
8
+ },
9
+ "platforms": {
10
+ "ubuntu": [
11
+
12
+ ],
13
+ "centos": [
14
+
15
+ ],
16
+ "redhat": [
17
+
18
+ ],
19
+ "debian": [
20
+
21
+ ]
22
+ },
23
+ "version": "0.7.0",
24
+ "recommendations": {
25
+ },
26
+ "name": "emacs",
27
+ "maintainer": "Opscode, Inc.",
28
+ "long_description": "",
29
+ "recipes": {
30
+ },
31
+ "suggestions": {
32
+ },
33
+ "maintainer_email": "cookbooks@opscode.com",
34
+ "attributes": {
35
+ },
36
+ "conflicting": {
37
+ },
38
+ "license": "Apache 2.0",
39
+ "providing": {
40
+ }
41
+ }
@@ -0,0 +1,3 @@
1
+ %w{ ubuntu debian fedora centos }.each do |os|
2
+ supports os
3
+ end
@@ -0,0 +1,21 @@
1
+ #
2
+ # Cookbook Name:: emacs
3
+ # Recipe:: default
4
+ #
5
+ # Copyright 2009, Opscode, Inc.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ package "emacs" do
20
+ action :upgrade
21
+ end
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "default",
3
+ "chef_type": "role",
4
+ "json_class": "Chef::Role",
5
+ "description": "The default role for all nodes.",
6
+ "run_list": [
7
+ "recipe[emacs]"
8
+ ]
9
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "web",
3
+ "chef_type": "role",
4
+ "json_class": "Chef::Role",
5
+ "description": "The base role for nodes that serve HTTP traffic",
6
+ "run_list": [
7
+ "role[default]"
8
+ ]
9
+ }
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ require 'maestro'
6
+ require 'shoulda'
7
+ require 'ftools'
8
+ require 'fileutils'
@@ -0,0 +1,805 @@
1
+ require "helper"
2
+ require "base_aws"
3
+
4
+
5
+ # Integration tests for Maestro::Cloud::Aws
6
+ class TestAwsCloud < Test::Unit::TestCase
7
+
8
+ include BaseAws
9
+
10
+ context "Maestro::Cloud::Aws" do
11
+
12
+ #######################
13
+ # Setup
14
+ #######################
15
+ setup do
16
+ ENV[Maestro::MAESTRO_DIR_ENV_VAR] = File.join(File.dirname(File.expand_path(__FILE__)), 'fixtures')
17
+ Maestro.create_log_dirs
18
+ credentials = @credentials
19
+ @cloud = aws_cloud :maestro_aws_itest do
20
+ keypair_name credentials[:keypair_name]
21
+ keypair_file credentials[:keypair_file]
22
+ aws_account_id credentials[:aws_account_id]
23
+ aws_access_key credentials[:aws_access_key]
24
+ aws_secret_access_key credentials[:aws_secret_access_key]
25
+ chef_bucket credentials[:chef_bucket]
26
+
27
+ roles do
28
+ role "web" do
29
+ public_ports [80, 443]
30
+ end
31
+ end
32
+
33
+ nodes do
34
+ elb_node "lb-1" do
35
+ availability_zones ["us-east-1b"]
36
+ listeners [{:load_balancer_port => 80, :instance_port => 80, :protocol => "http"}]
37
+ ec2_nodes ["node-1", "node-2"]
38
+ health_check(:target => "TCP:80", :timeout => 15, :interval => 60, :unhealthy_threshold => 5, :healthy_threshold => 3)
39
+ end
40
+
41
+ ec2_node "node-1" do
42
+ roles ["web"]
43
+ ami "ami-bb709dd2"
44
+ ssh_user "ubuntu"
45
+ instance_type "m1.small"
46
+ availability_zone "us-east-1b"
47
+ end
48
+
49
+ ec2_node "node-2" do
50
+ roles ["web"]
51
+ ami "ami-bb709dd2"
52
+ ssh_user "ubuntu"
53
+ instance_type "m1.small"
54
+ availability_zone "us-east-1b"
55
+ end
56
+
57
+ rds_node "db-1" do
58
+ engine "MySQL5.1"
59
+ db_instance_class "db.m1.small"
60
+ master_username "root"
61
+ master_user_password "password"
62
+ port 3306
63
+ allocated_storage 5
64
+ availability_zone "us-east-1b"
65
+ preferred_maintenance_window "Sun:03:00-Sun:07:00"
66
+ preferred_backup_window "03:00-05:00"
67
+ backup_retention_period 7
68
+ db_parameters [{:name => "character_set_server", :value => "utf8"},
69
+ {:name => "collation_server", :value => "utf8_bin"},
70
+ {:name => "long_query_time", :value => "5"}]
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+
77
+ #######################
78
+ # Teardown
79
+ #######################
80
+
81
+ teardown do
82
+ # terminate ec2 instances
83
+ instances = @ec2.describe_instances
84
+ to_be_terminated = Array.new
85
+ to_be_watched = Array.new
86
+ @cloud.ec2_nodes.each_pair do |node_name, node|
87
+ instance = @cloud.find_ec2_node_instance(node_name, instances)
88
+ if !instance.nil?
89
+ to_be_terminated << instance.instanceId
90
+ to_be_watched << node_name
91
+ end
92
+ end
93
+ if !to_be_terminated.empty?
94
+ puts "Terminating AWS integration test EC2 instances"
95
+ @ec2.terminate_instances(:instance_id => to_be_terminated)
96
+ end
97
+ STDOUT.sync = true
98
+ print "Waiting for Nodes #{to_be_watched.inspect} to terminate..." if !to_be_watched.empty?
99
+ while !to_be_watched.empty?
100
+ instances = @ec2.describe_instances()
101
+ to_be_watched.each do |node_name|
102
+ instance = @cloud.find_ec2_node_instance(node_name, instances)
103
+ if instance.nil?
104
+ puts ""
105
+ puts "Node #{node_name} terminated"
106
+ to_be_watched.delete(node_name)
107
+ print "Waiting for Nodes #{to_be_watched.inspect} to terminate..." if !to_be_watched.empty?
108
+ else
109
+ print "."
110
+ end
111
+ end
112
+ sleep 5 if !to_be_watched.empty?
113
+ end
114
+
115
+ # delete ELBs
116
+ balancers = @elb.describe_load_balancers()
117
+ to_be_deleted = Array.new
118
+ @cloud.elb_nodes.each_pair do |node_name, node|
119
+ instance = @cloud.find_elb_node_instance(node_name, balancers)
120
+ if !instance.nil?
121
+ to_be_deleted << node
122
+ end
123
+ end
124
+ if !to_be_deleted.empty?
125
+ puts "Deleting AWS integration test ELB instances"
126
+ to_be_deleted.each do |node|
127
+ puts "Deleting AWS integration test ELB: #{node.name}"
128
+ @elb.delete_load_balancer(:load_balancer_name => node.load_balancer_name)
129
+ end
130
+ end
131
+
132
+ # delete ec2 security groups
133
+ @cloud.ec2_security_groups.each do |group_name|
134
+ @ec2.delete_security_group(:group_name => group_name)
135
+ end
136
+
137
+ # delete RDS instances
138
+ all_instances = @rds.describe_db_instances
139
+ wait_for = Hash.new
140
+ to_be_terminated = Array.new
141
+ to_be_watched = Array.new
142
+ @cloud.rds_nodes.each_pair do |node_name, node|
143
+ node_instance = @cloud.find_rds_node_instance(node.db_instance_identifier, all_instances)
144
+ if !node_instance.nil?
145
+ if node_instance.DBInstanceStatus.eql?("deleting")
146
+ to_be_watched << node_name
147
+ elsif (node_instance.DBInstanceStatus.eql?("creating") ||
148
+ node_instance.DBInstanceStatus.eql?("rebooting") ||
149
+ node_instance.DBInstanceStatus.eql?("modifying") ||
150
+ node_instance.DBInstanceStatus.eql?("resetting-mastercredentials") ||
151
+ node_instance.DBInstanceStatus.eql?("backing-up"))
152
+ wait_for[node_name] = node_instance.DBInstanceStatus
153
+ elsif (node_instance.DBInstanceStatus.eql?("available") ||
154
+ node_instance.DBInstanceStatus.eql?("failed") ||
155
+ node_instance.DBInstanceStatus.eql?("storage-full"))
156
+ to_be_terminated << node_name
157
+ end
158
+ end
159
+ end
160
+
161
+ print "Waiting for AWS integration test RDS Nodes #{wait_for.inspect} to finish work before deleting. This may take several minutes..." if !wait_for.empty?
162
+ while !wait_for.empty?
163
+ instances = @rds.describe_db_instances
164
+ wait_for.each_pair do |node_name, status|
165
+ node = @cloud.rds_nodes[node_name]
166
+ node_instance = @cloud.find_rds_node_instance(node.db_instance_identifier, instances)
167
+ if (node_instance.DBInstanceStatus.eql?("available") ||
168
+ node_instance.DBInstanceStatus.eql?("failed") ||
169
+ node_instance.DBInstanceStatus.eql?("storage-full"))
170
+ puts ""
171
+ wait_for.delete(node_name)
172
+ to_be_terminated << node_name
173
+ print "Waiting for AWS integration test RDS Nodes #{wait_for.inspect} to finish work before deleting. This may take several minutes..." if !wait_for.empty?
174
+ else
175
+ print "."
176
+ end
177
+ end
178
+ sleep 5 if !wait_for.empty?
179
+ end
180
+
181
+ puts "Deleting AWS integration test RDS instances" if !to_be_terminated.empty?
182
+ to_be_terminated.each do |node_name|
183
+ node = @cloud.rds_nodes[node_name]
184
+ now = DateTime.now
185
+ final_snapshot = node.db_instance_identifier + "-" + now.to_s
186
+ puts "Deleting RDS instance #{node_name}..."
187
+ @rds.delete_db_instance(:db_instance_identifier => node.db_instance_identifier, :skip_final_snapshot => true)
188
+ to_be_watched << node_name
189
+ end
190
+ STDOUT.sync = true
191
+ print "Waiting for AWS integration test Nodes #{to_be_watched.inspect} to delete. This may take several minutes..." if !to_be_watched.empty?
192
+ while !to_be_watched.empty?
193
+ instances = @rds.describe_db_instances
194
+ to_be_watched.each do |node_name|
195
+ node = @cloud.rds_nodes[node_name]
196
+ instance = @cloud.find_rds_node_instance(node.db_instance_identifier, instances)
197
+ if instance.nil?
198
+ puts ""
199
+ puts "Node #{node_name} deleted"
200
+ to_be_watched.delete(node_name)
201
+ print "Waiting for Nodes #{to_be_watched.inspect} to delete. This may take several minutes..." if !to_be_watched.empty?
202
+ else
203
+ print "."
204
+ end
205
+ end
206
+ sleep 5 if !to_be_watched.empty?
207
+ end
208
+
209
+ # delete DB parameter groups
210
+ @cloud.rds_nodes.each_pair do |node_name, node|
211
+ if !node.db_parameters.nil?
212
+ begin
213
+ @rds.delete_db_parameter_group(:db_parameter_group_name => node.db_parameter_group_name)
214
+ puts "Deleted AWS integration test DB parameter group: #{node.db_parameter_group_name}"
215
+ rescue AWS::Error => aws_error
216
+ if !aws_error.message.eql? "DBParameterGroup #{node.db_parameter_group_name} not found."
217
+ # it didn't exist
218
+ end
219
+ end
220
+ end
221
+ end
222
+
223
+ # delete DB security groups
224
+ @cloud.rds_nodes.each_pair do |node_name, node|
225
+ begin
226
+ @rds.delete_db_security_group(:db_security_group_name => node.db_security_group_name)
227
+ puts "Deleted AWS integration test DB security group: #{node.db_security_group_name}"
228
+ rescue AWS::Error => aws_error
229
+ if !aws_error.message.eql? "DBSecurityGroup #{node.db_security_group_name} not found."
230
+ # it didn't exist
231
+ end
232
+ end
233
+ end
234
+
235
+ # delete DB snapshots
236
+ @cloud.rds_nodes.each_pair do |node_name, node|
237
+ begin
238
+ snapshots = @rds.describe_db_snapshots(:db_instance_identifier => node.db_instance_identifier)
239
+ if !snapshots.DescribeDBSnapshotsResult.DBSnapshots.nil?
240
+ snapshots.DescribeDBSnapshotsResult.DBSnapshots.DBSnapshot.each do |snapshot|
241
+ if snapshot.respond_to?(:DBSnapshotIdentifier)
242
+ @rds.delete_db_snapshot(:db_snapshot_identifier => snapshot.DBSnapshotIdentifier)
243
+ puts "Deleted AWS integration test DB snapshot: #{snapshot.DBSnapshotIdentifier}"
244
+ end
245
+ end
246
+ end
247
+ rescue AWS::Error => aws_error
248
+ puts aws_error
249
+ end
250
+ end
251
+
252
+ FileUtils.rm_rf([Maestro.maestro_log_directory], :secure => true) if File.exists?(Maestro.maestro_log_directory)
253
+ ENV.delete Maestro::MAESTRO_DIR_ENV_VAR
254
+ end
255
+
256
+
257
+ #######################
258
+ # Tests
259
+ #######################
260
+
261
+ should "be able to connect to AWS" do
262
+ assert_nothing_raised do
263
+ @cloud.connect!
264
+ end
265
+ end
266
+
267
+ should "report status" do
268
+ assert_nothing_raised do
269
+ @cloud.connect!
270
+ # not running code path
271
+ @cloud.status
272
+ end
273
+ end
274
+
275
+ should "not have any nodes running" do
276
+ instances = @ec2.describe_instances
277
+ @cloud.ec2_nodes.each_pair do |node_name, node|
278
+ assert @cloud.find_ec2_node_instance(node.name, instances).nil?
279
+ end
280
+ balancers = @elb.describe_load_balancers
281
+ @cloud.elb_nodes.each_pair do |node_name, node|
282
+ assert @cloud.find_elb_node_instance(node.name, balancers).nil?
283
+ end
284
+ db_instances = @rds.describe_db_instances
285
+ @cloud.rds_nodes.each_pair do |node_name, node|
286
+ assert @cloud.find_rds_node_instance(node.name, balancers).nil?
287
+ end
288
+ end
289
+
290
+ should "not have any rds db parameter groups" do
291
+ @cloud.db_parameter_groups.each do |group_name|
292
+ begin
293
+ group = @rds.describe_db_parameter_groups(:db_parameter_group_name => group_name)
294
+ assert false
295
+ rescue AWS::Error => aws_error
296
+ assert aws_error.message.eql? "DBParameterGroup #{group_name} not found."
297
+ end
298
+ end
299
+ end
300
+
301
+ should "ensure rds db parameter groups" do
302
+ assert_nothing_raised do
303
+ @cloud.connect!
304
+ # doesn't exist code path
305
+ @cloud.ensure_rds_db_parameter_groups
306
+ assert_rds_db_parameter_groups
307
+ # already exists code path
308
+ @cloud.ensure_rds_db_parameter_groups
309
+ assert_rds_db_parameter_groups
310
+ end
311
+ end
312
+
313
+ should "not have any rds db security groups" do
314
+ @cloud.db_security_groups.each do |group_name|
315
+ begin
316
+ group = @rds.describe_db_security_groups(:db_security_group_name => group_name)
317
+ assert false
318
+ rescue AWS::Error => aws_error
319
+ assert aws_error.message.eql? "DBSecurityGroup #{group_name} not found."
320
+ end
321
+ end
322
+ end
323
+
324
+ should "ensure rds db security groups" do
325
+ assert_nothing_raised do
326
+ @cloud.connect!
327
+ # doesn't exist code path
328
+ @cloud.ensure_rds_db_security_groups
329
+ assert_rds_db_security_groups
330
+ # already exists code path
331
+ @cloud.ensure_rds_db_security_groups
332
+ assert_rds_db_security_groups
333
+ end
334
+ end
335
+
336
+ should "not have any ec2 security groups" do
337
+ cloud_security_groups = @cloud.ec2_security_groups
338
+ cloud_security_groups.each do |group_name|
339
+ security_group = @ec2.describe_security_groups(:group_name => [group_name])
340
+ assert security_group.nil?
341
+ end
342
+ end
343
+
344
+ should "ensure ec2 security groups" do
345
+ assert_nothing_raised do
346
+ @cloud.connect!
347
+ # doesn't exist code path
348
+ @cloud.ensure_ec2_security_groups
349
+ assert_ec2_security_groups_created
350
+ assert_role_ec2_security_groups
351
+ # already exists code path
352
+ @cloud.ensure_ec2_security_groups
353
+ assert_ec2_security_groups_created
354
+ assert_role_ec2_security_groups
355
+ end
356
+ end
357
+
358
+ should "ensure nodes running" do
359
+ assert_nothing_raised do
360
+ @cloud.connect!
361
+ @cloud.ensure_rds_security_groups
362
+ @cloud.ensure_rds_db_parameter_groups
363
+ @cloud.ensure_ec2_security_groups
364
+ @cloud.ensure_rds_db_security_groups
365
+ # not running code path
366
+ @cloud.ensure_nodes_running
367
+ assert_rds_nodes_running
368
+ assert_ec2_nodes_running
369
+ assert_elb_nodes_running
370
+ # already running code path
371
+ @cloud.ensure_nodes_running
372
+ assert_rds_nodes_running
373
+ assert_ec2_nodes_running
374
+ assert_elb_nodes_running
375
+ end
376
+ end
377
+
378
+ should "not find a bogus elastic ip allocated" do
379
+ assert_nothing_raised do
380
+ @cloud.connect!
381
+ assert !@cloud.elastic_ip_allocated?("127.0.0.1")
382
+ end
383
+ end
384
+
385
+ should "find an allocated elastic ip" do
386
+ assert_nothing_raised do
387
+ @cloud.connect!
388
+ elastic_ip = @ec2.allocate_address
389
+ assert @cloud.elastic_ip_allocated?(elastic_ip.publicIp)
390
+ end
391
+ end
392
+
393
+ should "ensure elastic ips" do
394
+ assert_nothing_raised do
395
+ @cloud.nodes.delete("lb-1")
396
+ @cloud.elb_nodes.delete("lb-1")
397
+ @cloud.nodes.delete("db-1")
398
+ @cloud.rds_nodes.delete("db-1")
399
+ # case 1: associate an Elastic IP to node_1
400
+ elastic_ip = @ec2.allocate_address
401
+ @cloud.nodes["node-1"].elastic_ip(elastic_ip.publicIp)
402
+ @cloud.connect!
403
+ @cloud.ensure_ec2_security_groups
404
+ @cloud.ensure_nodes_running
405
+ @cloud.ensure_elastic_ips
406
+ instances = @ec2.describe_instances
407
+ instance = @cloud.find_ec2_node_instance("node-1", instances)
408
+ instance_id = @cloud.elastic_ip_association(elastic_ip.publicIp)
409
+ assert instance_id.eql?(instance.instanceId)
410
+ # case 2: disassociate Elastic IP from node_1 and associate with node_2
411
+ @cloud.nodes["node-1"].elastic_ip(nil)
412
+ @cloud.nodes["node-2"].elastic_ip(elastic_ip.publicIp)
413
+ @cloud.ensure_elastic_ips
414
+ instances = @ec2.describe_instances
415
+ node_1_instance = @cloud.find_ec2_node_instance("node-1", instances)
416
+ node_2_instance = @cloud.find_ec2_node_instance("node-2", instances)
417
+ instance_id = @cloud.elastic_ip_association(elastic_ip.publicIp)
418
+ assert instance_id.eql?(node_2_instance.instanceId)
419
+ # case 3: Elastic IP already associated, do nothing
420
+ @cloud.ensure_elastic_ips
421
+ instance_id = @cloud.elastic_ip_association(elastic_ip.publicIp)
422
+ assert instance_id.eql?(node_2_instance.instanceId)
423
+ end
424
+ end
425
+
426
+ should "not find a bogus ebs volume allocated" do
427
+ assert_nothing_raised do
428
+ @cloud.connect!
429
+ assert !@cloud.ebs_volume_allocated?("vol-abcd1234")
430
+ end
431
+ end
432
+
433
+ should "find an ebs volume allocated" do
434
+ assert_nothing_raised do
435
+ @cloud.connect!
436
+ volume = @ec2.create_volume(:availability_zone => "us-east-1b", :size => "1")
437
+ to_be_watched = [volume.volumeId]
438
+ while !to_be_watched.empty?
439
+ volumes = @ec2.describe_volumes(:volume_id => to_be_watched[0])
440
+ if volumes.volumeSet.item[0].status.eql? "available"
441
+ to_be_watched.clear
442
+ end
443
+ sleep 5 if !to_be_watched.empty?
444
+ end
445
+ assert @cloud.ebs_volume_allocated?(volume.volumeId)
446
+ end
447
+ end
448
+
449
+ should "ensure ebs volumes" do
450
+ assert_nothing_raised do
451
+ @cloud.nodes.delete("lb-1")
452
+ @cloud.elb_nodes.delete("lb-1")
453
+ @cloud.nodes.delete("db-1")
454
+ @cloud.rds_nodes.delete("db-1")
455
+ # case 1: create an EBS volume and attach it to node-1
456
+ volume = @ec2.create_volume(:availability_zone => "us-east-1b", :size => "1")
457
+ to_be_watched = [volume.volumeId]
458
+ while !to_be_watched.empty?
459
+ volumes = @ec2.describe_volumes(:volume_id => to_be_watched[0])
460
+ if volumes.volumeSet.item[0].status.eql? "available"
461
+ to_be_watched.clear
462
+ end
463
+ sleep 5 if !to_be_watched.empty?
464
+ end
465
+ @cloud.nodes["node-1"].ebs_volume_id(volume.volumeId)
466
+ @cloud.nodes["node-1"].ebs_device("/dev/sdh")
467
+ @cloud.connect!
468
+ @cloud.ensure_ec2_security_groups
469
+ @cloud.ensure_nodes_running
470
+ @cloud.ensure_ebs_volumes
471
+ instances = @ec2.describe_instances
472
+ node_1_instance = @cloud.find_ec2_node_instance("node-1", instances)
473
+ node_2_instance = @cloud.find_ec2_node_instance("node-2", instances)
474
+ instance_id = @cloud.ebs_volume_association(volume.volumeId)
475
+ assert instance_id.eql?(node_1_instance.instanceId)
476
+ # case 2: detach EBS volume from node_1 and attach it to node_2
477
+ @cloud.nodes["node-1"].ebs_volume_id(nil)
478
+ @cloud.nodes["node-1"].ebs_device(nil)
479
+ @cloud.nodes["node-2"].ebs_volume_id(volume.volumeId)
480
+ @cloud.nodes["node-2"].ebs_device("/dev/sdh")
481
+ @cloud.ensure_ebs_volumes
482
+ instance_id = @cloud.ebs_volume_association(volume.volumeId)
483
+ assert instance_id.eql?(node_2_instance.instanceId)
484
+ # case 3: EBS Volumes already associated, do nothing
485
+ @cloud.ensure_ebs_volumes
486
+ instance_id = @cloud.ebs_volume_association(volume.volumeId)
487
+ assert instance_id.eql?(node_2_instance.instanceId)
488
+ end
489
+ end
490
+
491
+ should "start clean" do
492
+ assert_nothing_raised do
493
+ elastic_ip = @ec2.allocate_address
494
+ @cloud.nodes["node-1"].elastic_ip(elastic_ip.publicIp)
495
+ volume = @ec2.create_volume(:availability_zone => "us-east-1b", :size => "1")
496
+ to_be_watched = [volume.volumeId]
497
+ while !to_be_watched.empty?
498
+ volumes = @ec2.describe_volumes(:volume_id => to_be_watched[0])
499
+ if volumes.volumeSet.item[0].status.eql? "available"
500
+ to_be_watched.clear
501
+ end
502
+ sleep 5 if !to_be_watched.empty?
503
+ end
504
+ @cloud.nodes["node-2"].ebs_volume_id(volume.volumeId)
505
+ @cloud.nodes["node-2"].ebs_device("/dev/sdh")
506
+ @cloud.connect!
507
+ @cloud.start
508
+ assert_rds_db_parameter_groups
509
+ assert_ec2_security_groups_created
510
+ assert_role_ec2_security_groups
511
+ assert_rds_db_security_groups
512
+ assert_rds_nodes_running
513
+ assert_ec2_nodes_running
514
+ assert_elb_nodes_running
515
+ instances = @ec2.describe_instances
516
+ node_1_instance = @cloud.find_ec2_node_instance("node-1", instances)
517
+ node_2_instance = @cloud.find_ec2_node_instance("node-2", instances)
518
+ elastic_ip_instance_id = @cloud.elastic_ip_association(elastic_ip.publicIp)
519
+ assert elastic_ip_instance_id.eql?(node_1_instance.instanceId)
520
+ ebs_volume_instance_id = @cloud.ebs_volume_association(volume.volumeId)
521
+ assert ebs_volume_instance_id.eql?(node_2_instance.instanceId)
522
+ # running status code path
523
+ @cloud.status
524
+ end
525
+ end
526
+
527
+ should "upload Chef assets" do
528
+ assert_nothing_raised do
529
+ @cloud.connect!
530
+ @cloud.upload_chef_assets
531
+ bucket = AWS::S3::Bucket.find(@cloud.chef_bucket)
532
+ assert !bucket.nil?
533
+ assert !bucket[Maestro::MAESTRO_CHEF_ARCHIVE].nil?
534
+ end
535
+ end
536
+
537
+ should "configure nodes" do
538
+ assert_nothing_raised do
539
+ @cloud.nodes.delete("lb-1")
540
+ @cloud.elb_nodes.delete("lb-1")
541
+ @cloud.nodes.delete("db-1")
542
+ @cloud.rds_nodes.delete("db-1")
543
+ @cloud.connect!
544
+ @cloud.start
545
+ @cloud.configure
546
+ assert_ec2_security_groups_created
547
+ assert_role_ec2_security_groups
548
+ assert_ec2_nodes_running
549
+ end
550
+ end
551
+
552
+ should "ensure nodes terminated" do
553
+ assert_nothing_raised do
554
+ @cloud.connect!
555
+ @cloud.start
556
+ @cloud.ensure_nodes_terminated
557
+ assert_elb_nodes_not_running
558
+ assert_ec2_nodes_not_running
559
+ assert_rds_nodes_not_running
560
+ end
561
+ end
562
+
563
+ should "shutdown clean" do
564
+ assert_nothing_raised do
565
+ @cloud.connect!
566
+ @cloud.start
567
+ @cloud.shutdown
568
+ assert_elb_nodes_not_running
569
+ assert_ec2_nodes_not_running
570
+ assert_rds_nodes_not_running
571
+ end
572
+ end
573
+ end
574
+
575
+
576
+ ################################
577
+ # Assertion helper methods
578
+ ################################
579
+
580
+ # asserts that all of the Cloud's EC2 security groups have been created
581
+ def assert_ec2_security_groups_created
582
+ cloud_security_groups = @cloud.ec2_security_groups
583
+ cloud_security_groups.each do |group_name|
584
+ security_group = @ec2.describe_security_groups(:group_name => [group_name])
585
+ assert !security_group.nil?
586
+ end
587
+ end
588
+
589
+ # asserts that the Cloud's Role EC2 security groups have been configured correctly
590
+ def assert_role_ec2_security_groups
591
+ role_security_groups = @cloud.role_ec2_security_groups
592
+ role_security_groups.each do |group_name|
593
+ security_group = @ec2.describe_security_groups(:group_name => [group_name])
594
+ assert !security_group.nil?
595
+ if group_name.eql? @cloud.default_ec2_security_group
596
+ assert_default_ec2_security_group(security_group)
597
+ else
598
+ assert_role_ec2_security_group(security_group)
599
+ end
600
+ end
601
+ end
602
+
603
+ # asserts the default EC2 security group has been configured correctly
604
+ def assert_default_ec2_security_group(security_group)
605
+ assert !security_group.securityGroupInfo.item[0].ipPermissions.nil?
606
+ assert !security_group.securityGroupInfo.item[0].ipPermissions.item.nil?
607
+ assert !security_group.securityGroupInfo.item[0].ipPermissions.item.empty?
608
+ assert security_group.securityGroupInfo.item[0].ipPermissions.item.size == 4
609
+ ip_permissions = security_group.securityGroupInfo.item[0].ipPermissions.item
610
+ found_default_icmp = false
611
+ found_default_tcp = false
612
+ found_default_udp = false
613
+ found_ssh = false
614
+ ip_permissions.each do |permission|
615
+ if permission.groups.nil?
616
+ assert !permission.fromPort.nil?
617
+ assert permission.fromPort.eql?("22")
618
+ assert !permission.toPort.nil?
619
+ assert permission.toPort.eql?("22")
620
+ assert !permission.ipProtocol.nil?
621
+ assert permission.ipProtocol.eql?("tcp")
622
+ found_ssh = true
623
+ else
624
+ assert !permission.groups.item.nil?
625
+ assert permission.groups.item.size == 1
626
+ assert permission.groups.item[0].groupName.eql?(@cloud.default_ec2_security_group)
627
+ assert permission.groups.item[0].userId.gsub(/-/,'').eql?(@cloud.aws_account_id.gsub(/-/,''))
628
+ if permission.ipProtocol.eql?("icmp")
629
+ found_default_icmp = true
630
+ assert permission.fromPort.eql?("-1")
631
+ assert permission.toPort.eql?("-1")
632
+ elsif permission.ipProtocol.eql?("tcp")
633
+ found_default_tcp = true
634
+ assert permission.fromPort.eql?("1")
635
+ assert permission.toPort.eql?("65535")
636
+ elsif permission.ipProtocol.eql?("udp")
637
+ found_default_udp = true
638
+ assert permission.fromPort.eql?("1")
639
+ assert permission.toPort.eql?("65535")
640
+ end
641
+ end
642
+ end
643
+ assert found_default_icmp
644
+ assert found_default_tcp
645
+ assert found_default_udp
646
+ assert found_ssh
647
+ end
648
+
649
+ # asserts a Role EC2 security group is configured correctly
650
+ def assert_role_ec2_security_group(security_group)
651
+ role_security_groups = @cloud.role_ec2_security_groups
652
+ @cloud.roles.values.each do |role|
653
+ role_security_group_name = @cloud.role_ec2_security_group_name(role.name)
654
+ assert !role_security_group_name.nil?
655
+ role_security_group = role_security_groups.find {|group| group.eql? role_security_group_name}
656
+ assert !role_security_group.nil?
657
+ assert !security_group.securityGroupInfo.nil?
658
+ assert !security_group.securityGroupInfo.item.nil?
659
+ assert !security_group.securityGroupInfo.item.empty?
660
+ if !role.public_ports.nil?
661
+ role.public_ports.each do |port|
662
+ found_port = false
663
+ security_group.securityGroupInfo.item.each do |item|
664
+ if !item.ipPermissions.nil?
665
+ item.ipPermissions.item.each do |permission|
666
+ if permission.fromPort.eql?(port.to_s) && permission.toPort.eql?(port.to_s)
667
+ found_port = true
668
+ end
669
+ end
670
+ assert found_port
671
+ end
672
+ end
673
+ end
674
+ end
675
+ end
676
+ end
677
+
678
+ # asserts that the test Cloud's Ec2 Nodes are running and security groups applied correctly
679
+ def assert_ec2_nodes_running
680
+ instances = @ec2.describe_instances
681
+ @cloud.ec2_nodes.each_pair do |node_name, node|
682
+ instance = @cloud.find_ec2_node_instance(node_name, instances)
683
+ assert !instance.nil?
684
+ this_instance = @ec2.describe_instances(:instance_id => [instance.instanceId])
685
+ assert !this_instance.nil?
686
+ assert this_instance.reservationSet.item.size == 1
687
+ assert this_instance.reservationSet.item[0].groupSet.item.size == node.security_groups.size
688
+ node.security_groups.each do |node_group|
689
+ assert this_instance.reservationSet.item[0].groupSet.item.any? {|group| group.groupId.eql? node_group}
690
+ end
691
+ end
692
+ end
693
+
694
+ # asserts that the test Cloud's Nodes are not running
695
+ def assert_ec2_nodes_not_running
696
+ instances = @ec2.describe_instances
697
+ @cloud.ec2_nodes.each_pair do |node_name, node|
698
+ instance = @cloud.find_ec2_node_instance(node_name, instances)
699
+ assert instance.nil?
700
+ end
701
+ end
702
+
703
+ # asserts that the test Cloud's Elb Nodes are running and configured correctly
704
+ def assert_elb_nodes_running
705
+ elb_instances = @elb.describe_load_balancers
706
+ @cloud.elb_nodes.each_pair do |node_name, node|
707
+ elb_instance = @cloud.find_elb_node_instance(node_name, elb_instances)
708
+ assert !elb_instance.nil?
709
+ assert elb_instance.LoadBalancerName.eql? node.load_balancer_name
710
+ assert elb_instance.AvailabilityZones.member[0].eql? "us-east-1b"
711
+ assert elb_instance.Listeners.member[0].InstancePort.eql? "80"
712
+ assert elb_instance.Listeners.member[0].Protocol.eql? "HTTP"
713
+ assert elb_instance.Listeners.member[0].LoadBalancerPort.eql? "80"
714
+ assert elb_instance.HealthCheck.HealthyThreshold.eql? "3"
715
+ assert elb_instance.HealthCheck.Timeout.eql? "15"
716
+ assert elb_instance.HealthCheck.UnhealthyThreshold.eql? "5"
717
+ assert elb_instance.HealthCheck.Interval.eql? "60"
718
+ assert !elb_instance.Instances.nil?
719
+ assert !elb_instance.Instances.member.nil?
720
+ assert !elb_instance.Instances.member.empty?
721
+ registered_ec2_instance_ids = Array.new
722
+ elb_instance.Instances.member.each {|member| registered_ec2_instance_ids << member.InstanceId}
723
+ ec2_instances = @ec2.describe_instances
724
+ @cloud.ec2_nodes.each_pair do |ec2_node_name, ec2_node|
725
+ ec2_instance = @cloud.find_ec2_node_instance(ec2_node_name, ec2_instances)
726
+ assert registered_ec2_instance_ids.include?(ec2_instance.instanceId)
727
+ end
728
+ assert node.ec2_nodes.size == registered_ec2_instance_ids.size
729
+ end
730
+ end
731
+
732
+ # asserts that the test Cloud's Elb Nodes are not running
733
+ def assert_elb_nodes_not_running
734
+ instances = @elb.describe_load_balancers
735
+ @cloud.elb_nodes.each_pair do |node_name, node|
736
+ instance = @cloud.find_elb_node_instance(node_name, instances)
737
+ assert instance.nil?
738
+ end
739
+ end
740
+
741
+ # asserts that the test Cloud's Rds Nodes' db parameter groups are created and configured correctly
742
+ def assert_rds_db_parameter_groups
743
+ @cloud.rds_nodes.each_pair do |name, node|
744
+ params = Hash.new
745
+ node.db_parameters.each {|hash| params[hash[:name]] = hash[:value]}
746
+ begin
747
+ parameters = @rds.describe_db_parameters(:db_parameter_group_name => node.db_parameter_group_name)
748
+ assert !parameters.nil?
749
+ parameters.DescribeDBParametersResult.Parameters.Parameter.each do |p|
750
+ params.delete(p.ParameterName) if params.has_key?(p.ParameterName) && !p.ParameterValue.nil? && params[p.ParameterName].eql?(p.ParameterValue)
751
+ end
752
+ while !parameters.DescribeDBParametersResult.Marker.nil?
753
+ parameters = @rds.describe_db_parameters(:db_parameter_group_name => node.db_parameter_group_name, :marker => parameters.DescribeDBParametersResult.Marker)
754
+ assert !parameters.nil?
755
+ parameters.DescribeDBParametersResult.Parameters.Parameter.each do |p|
756
+ params.delete(p.ParameterName) if params.has_key?(p.ParameterName) && !p.ParameterValue.nil? && params[p.ParameterName].eql?(p.ParameterValue)
757
+ end
758
+ end
759
+ rescue AWS::Error => aws_error
760
+ assert false if aws_error.message.eql? "DBParameterGroup not found: #{node.db_parameter_group_name}"
761
+ end
762
+ assert params.empty?
763
+ end
764
+ end
765
+
766
+ # asserts that the test Cloud's Rds Nodes' db security groups are created and configured correctly
767
+ def assert_rds_db_security_groups
768
+ @cloud.rds_nodes.each_pair do |name, node|
769
+ begin
770
+ group = @rds.describe_db_security_groups(:db_security_group_name => node.db_security_group_name)
771
+ assert !group.nil?
772
+ assert group.DescribeDBSecurityGroupsResult.DBSecurityGroups.DBSecurityGroup.EC2SecurityGroups.EC2SecurityGroup.EC2SecurityGroupName.eql? @cloud.default_ec2_security_group
773
+ rescue AWS::Error => aws_error
774
+ assert false if aws_error.message.eql? "DBSecurityGroup not found: #{node.db_security_group_name}"
775
+ end
776
+ end
777
+ end
778
+
779
+ # asserts that the test Cloud's Rds Nodes are running and configured correctly
780
+ def assert_rds_nodes_running
781
+ db_instances = @rds.describe_db_instances
782
+ @cloud.rds_nodes.each_pair do |node_name, node|
783
+ rds_instance = @cloud.find_rds_node_instance(node.db_instance_identifier, db_instances)
784
+ assert !rds_instance.nil?
785
+ assert rds_instance.PreferredMaintenanceWindow.eql? node.preferred_maintenance_window.downcase
786
+ assert rds_instance.Engine.eql? node.engine.downcase
787
+ assert rds_instance.MasterUsername.eql? node.master_username
788
+ assert rds_instance.DBInstanceClass.eql? node.db_instance_class
789
+ assert rds_instance.BackupRetentionPeriod.eql? node.backup_retention_period.to_s
790
+ assert rds_instance.DBInstanceIdentifier.eql? node.db_instance_identifier
791
+ assert rds_instance.AllocatedStorage.eql? node.allocated_storage.to_s
792
+ assert rds_instance.AvailabilityZone.eql? node.availability_zone
793
+ assert rds_instance.PreferredBackupWindow.eql? node.preferred_backup_window
794
+ end
795
+ end
796
+
797
+ # asserts that the test Cloud's Rds Nodes are not running
798
+ def assert_rds_nodes_not_running
799
+ db_instances = @rds.describe_db_instances
800
+ @cloud.rds_nodes.each_pair do |node_name, node|
801
+ rds_instance = @cloud.find_rds_node_instance(node.db_instance_identifier, db_instances)
802
+ assert rds_instance.nil?
803
+ end
804
+ end
805
+ end