maws 0.8.0

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.
Files changed (50) hide show
  1. data/bin/maws +10 -0
  2. data/lib/maws/chunk_source.rb +41 -0
  3. data/lib/maws/command.rb +62 -0
  4. data/lib/maws/command_loader.rb +28 -0
  5. data/lib/maws/command_options_parser.rb +37 -0
  6. data/lib/maws/commands/configure.rb +287 -0
  7. data/lib/maws/commands/console.rb +38 -0
  8. data/lib/maws/commands/create.rb +25 -0
  9. data/lib/maws/commands/describe.rb +15 -0
  10. data/lib/maws/commands/destroy.rb +11 -0
  11. data/lib/maws/commands/elb-add.rb +17 -0
  12. data/lib/maws/commands/elb-describe.rb +23 -0
  13. data/lib/maws/commands/elb-disable-zones.rb +17 -0
  14. data/lib/maws/commands/elb-enable-zones.rb +18 -0
  15. data/lib/maws/commands/elb-remove.rb +16 -0
  16. data/lib/maws/commands/set-prefix.rb +24 -0
  17. data/lib/maws/commands/set-security-groups.rb +442 -0
  18. data/lib/maws/commands/start.rb +11 -0
  19. data/lib/maws/commands/status.rb +25 -0
  20. data/lib/maws/commands/stop.rb +11 -0
  21. data/lib/maws/commands/teardown.rb +11 -0
  22. data/lib/maws/commands/volumes-cleanup.rb +22 -0
  23. data/lib/maws/commands/volumes-status.rb +43 -0
  24. data/lib/maws/commands/wait.rb +61 -0
  25. data/lib/maws/connection.rb +121 -0
  26. data/lib/maws/core_ext/object.rb +5 -0
  27. data/lib/maws/description/ebs.rb +40 -0
  28. data/lib/maws/description/ec2.rb +72 -0
  29. data/lib/maws/description/elb.rb +52 -0
  30. data/lib/maws/description/rds.rb +47 -0
  31. data/lib/maws/description.rb +78 -0
  32. data/lib/maws/instance/ebs.rb +45 -0
  33. data/lib/maws/instance/ec2.rb +144 -0
  34. data/lib/maws/instance/elb.rb +92 -0
  35. data/lib/maws/instance/rds.rb +84 -0
  36. data/lib/maws/instance.rb +167 -0
  37. data/lib/maws/instance_collection.rb +98 -0
  38. data/lib/maws/instance_display.rb +84 -0
  39. data/lib/maws/instance_matcher.rb +27 -0
  40. data/lib/maws/loader.rb +173 -0
  41. data/lib/maws/logger.rb +66 -0
  42. data/lib/maws/mash.rb +9 -0
  43. data/lib/maws/maws.rb +102 -0
  44. data/lib/maws/profile_loader.rb +92 -0
  45. data/lib/maws/specification.rb +127 -0
  46. data/lib/maws/ssh.rb +7 -0
  47. data/lib/maws/trollop.rb +782 -0
  48. data/lib/maws/volumes_command.rb +29 -0
  49. data/lib/maws.rb +25 -0
  50. metadata +115 -0
@@ -0,0 +1,121 @@
1
+ require 'right_aws'
2
+ require 'maws/mash'
3
+ require 'maws/description'
4
+
5
+ class Connection
6
+ attr_reader :ec2, :rds, :elb
7
+
8
+ def initialize(config)
9
+ @config = config
10
+
11
+ @access_key_id = @config.aws_key.key_id
12
+ @secret_key = @config.aws_key.secret_key
13
+
14
+ @params = {:region => @config.region, :logger => $right_aws_logger}
15
+ end
16
+
17
+ def connect(services)
18
+ # The right_aws gem parses the EC2_URL environment variable if it is set. The EC2 CLI tools also use that variable
19
+ # but expect the hostname to be region-specific (e.g., us-east-1.ec2.amazonaws.com) instead of generic
20
+ # (e.g., ec2.amazonaws.com). To avoid conflicts, unset the variable here and use the right_aws default value.
21
+ ENV["EC2_URL"] = nil
22
+
23
+ # always connect to ec2
24
+ @ec2 = RightAws::Ec2.new(@access_key_id, @secret_key, @params.dup)
25
+
26
+ if services.include?(:rds)
27
+ @rds = RightAws::RdsInterface.new(@access_key_id, @secret_key, @params.dup)
28
+ end
29
+
30
+ if services.include?(:elb)
31
+ @elb = RightAws::ElbInterface.new(@access_key_id, @secret_key, @params.dup)
32
+ end
33
+ end
34
+
35
+ def available_zones
36
+ ec2.describe_availability_zones.
37
+ find_all{ |zone_description| zone_description[:zone_state] == "available"}.
38
+ map { |zone_description| zone_description[:zone_name][/\w$/]}
39
+ end
40
+
41
+ def image_id_for_image_name(image_name)
42
+ return if image_name.nil? || image_name.empty?
43
+ images = @ec2.describe_images(:filters => { 'tag:Name' => image_name})
44
+ if images.empty?
45
+ error "No AMI with name '#{image_name}'"
46
+ elsif images.count > 1
47
+ error "Ambigous AMI name: '#{image_name}'. Several AMIs match it #{images.collect{|i| i[:aws_id]}.join(', ')}"
48
+ else
49
+ images.first[:aws_id]
50
+ end
51
+ end
52
+
53
+ def descriptions(services = nil)
54
+ services ||= :all
55
+ descriptions = []
56
+
57
+ descriptions += ec2_descriptions if services == :all or services.include?(:ec2)
58
+ descriptions += rds_descriptions if services == :all or services.include?(:rds)
59
+ descriptions += elb_descriptions if services == :all or services.include?(:elb)
60
+
61
+ descriptions
62
+ end
63
+
64
+ def ec2_descriptions
65
+ # convert aws description to Description
66
+ descriptions = descriptions = ec2.describe_instances.map {|description|
67
+ description[:service] = :ec2
68
+ Description.create(description)
69
+ }
70
+
71
+ # filter out terminated when same name exists as a living one and terminated
72
+ by_name = descriptions.group_by { |d| d.name }
73
+
74
+ # if there is one than more for the same name: delete terminated descriptions, take the last one (trust AWS sorting)
75
+ by_name.map {|name, descriptions|
76
+ if descriptions.count > 1
77
+ descriptions.delete_if {|d| d.status == "terminated"}
78
+ descriptions.replace([descriptions.last]).compact!
79
+ end
80
+ }
81
+
82
+ filter_current_profile_prefix(by_name.values.flatten)
83
+ end
84
+
85
+ def rds_descriptions
86
+ return [] unless rds
87
+
88
+ descriptions = rds.describe_db_instances.map { |description|
89
+ description[:service] = :rds
90
+ Description.create(description)
91
+ }
92
+
93
+ filter_current_profile_prefix(descriptions)
94
+ end
95
+
96
+ def elb_descriptions
97
+ return [] unless elb
98
+
99
+ descriptions = elb.describe_load_balancers.map { |description|
100
+ description[:service] = :elb
101
+ Description.create(description)
102
+ }
103
+
104
+ filter_current_profile_prefix(descriptions)
105
+ end
106
+
107
+ def ebs_descriptions
108
+ descriptions = ec2.describe_volumes.map { |description|
109
+ description[:service] = :ebs
110
+ Description.create(description)
111
+ }
112
+
113
+ filter_current_profile_prefix(descriptions)
114
+ end
115
+
116
+ private
117
+
118
+ def filter_current_profile_prefix(descriptions)
119
+ descriptions.delete_if {|d| d.profile != @config.profile.name || d.prefix != @config.prefix}
120
+ end
121
+ end
@@ -0,0 +1,5 @@
1
+ class Object
2
+ def blank?
3
+ respond_to?(:empty?) ? empty? : !self
4
+ end
5
+ end
@@ -0,0 +1,40 @@
1
+ class Description::EBS < Description
2
+ def initialize(description)
3
+ description[:service] ||= :ebs
4
+ @description = description
5
+ end
6
+
7
+ def name
8
+ (tags && tags["Name"]) || aws_id
9
+ end
10
+
11
+ def status
12
+ aws_status
13
+ end
14
+
15
+ def region_zone
16
+ description[:zone]
17
+ end
18
+ end
19
+
20
+ # example EBS volume descriptions
21
+ # [{:snapshot_id=>"snap-a536ecc0",
22
+ # :service => :ebs, # this is set by maws
23
+ # :aws_id=>"vol-85fe67e8",
24
+ # :aws_status=>"available",
25
+ # :aws_created_at=>"2011-12-15T18:47:26.000Z",
26
+ # :zone=>"us-east-1c",
27
+ # :tags=>{},
28
+ # :aws_size=>100},
29
+ # {:aws_device=>"/dev/sda",
30
+ # :snapshot_id=>"snap-35446157",
31
+ # :aws_id=>"vol-6ce63401",
32
+ # :aws_status=>"in-use",
33
+ # :aws_created_at=>"2011-11-19T22:45:03.000Z",
34
+ # :aws_attachment_status=>"attached",
35
+ # :zone=>"us-east-1c",
36
+ # :tags=>{"Name"=>"foo-e2e-control-1"},
37
+ # :aws_size=>6,
38
+ # :aws_attached_at=>"2011-11-19T22:45:24.000Z",
39
+ # :aws_instance_id=>"i-fd126f9e",
40
+ # :delete_on_termination=>true},
@@ -0,0 +1,72 @@
1
+ class Description::EC2 < Description
2
+ def initialize(description)
3
+ description[:service] ||= :ec2
4
+ @description = description
5
+ end
6
+
7
+ def name
8
+ (tags && tags["Name"]) || aws_instance_id
9
+ end
10
+
11
+ def aws_id
12
+ aws_instance_id
13
+ end
14
+
15
+ def status
16
+ aws_state
17
+ end
18
+
19
+ def region_zone
20
+ aws_availability_zone
21
+ end
22
+
23
+ def ebs_volumes
24
+ block_device_mappings || []
25
+ end
26
+
27
+ def ebs_volume_ids
28
+ ebs_volumes.map {|v| v[:ebs_volume_id]}
29
+ end
30
+
31
+ def attached_ebs_volume_ids
32
+ ebs_volumes.find_all{|v| v[:ebs_status] == 'attached'}.map {|v| v[:ebs_volume_id]}
33
+ end
34
+ end
35
+
36
+
37
+ # example ec2 description
38
+ # {:private_ip_address=>"10.240.7.99",
39
+ # :service => :ec2, # this is set by maws
40
+ # :aws_image_id=>"ami-c2a3f5d4",
41
+ # :ip_address=>"174.129.134.109",
42
+ # :dns_name=>"ec2-174-129-134-109.compute-1.amazonaws.com",
43
+ # :aws_instance_type=>"m1.small",
44
+ # :aws_owner=>"826693181925",
45
+ # :root_device_name=>"/dev/sda1",
46
+ # :instance_class=>"elastic",
47
+ # :aws_state=>"running",
48
+ # :private_dns_name=>"domU-12-31-39-04-00-95.compute-1.internal",
49
+ # :aws_reason=>"",
50
+ # :aws_launch_time=>"2009-11-18T14:03:25.000Z",
51
+ # :aws_reservation_id=>"r-54d38542",
52
+ # :aws_state_code=>16,
53
+ # :ami_launch_index=>"0",
54
+ # :aws_availability_zone=>"us-east-1a",
55
+ # :aws_groups=>["default"],
56
+ # :monitoring_state=>"disabled",
57
+ # :aws_product_codes=>[],
58
+ # :tags => {"Name" => "foo-test-web-01"}
59
+ # :ssh_key_name=>"",
60
+ # :block_device_mappings=>
61
+ # [{:ebs_status=>"attached",
62
+ # :ebs_delete_on_termination=>true,
63
+ # :ebs_attach_time=>"2009-11-18T14:03:34.000Z",
64
+ # :device_name=>"/dev/sda1",
65
+ # :ebs_volume_id=>"vol-e600f98f"},
66
+ # {:ebs_status=>"attached",
67
+ # :ebs_delete_on_termination=>true,
68
+ # :ebs_attach_time=>"2009-11-18T14:03:34.000Z",
69
+ # :device_name=>"/dev/sdk",
70
+ # :ebs_volume_id=>"vol-f900f990"}],
71
+ # :aws_instance_id=>"i-8ce84ae4"}
72
+
@@ -0,0 +1,52 @@
1
+ class Description::ELB < Description
2
+ def initialize(description)
3
+ description[:service] ||= :elb
4
+ @description = description
5
+ end
6
+
7
+ def region_zone
8
+ # take from AZs it supports, ELBs always have at least one AZ
9
+ availability_zones.first
10
+ end
11
+
12
+ def physical_zone
13
+ nil
14
+ end
15
+
16
+ def name
17
+ description[:load_balancer_name]
18
+ end
19
+
20
+ def aws_id
21
+ description[:load_balancer_name]
22
+ end
23
+
24
+ def status
25
+ 'available' if description[:load_balancer_name]
26
+ end
27
+
28
+ def enabled_zones
29
+ availability_zones.map {|z| z[-1,1]}
30
+ end
31
+ end
32
+
33
+ # example elb description
34
+ # {:availability_zones=>["us-east-1c"],
35
+ # :service => :elb, # this is set by maws
36
+ # :dns_name=>"foo-lb-110916812.us-east-1.elb.amazonaws.com",
37
+ # :created_time=>"2011-07-06T23:50:06.040Z",
38
+ # :health_check=>
39
+ # {:timeout=>5,
40
+ # :target=>"HTTP:80/",
41
+ # :interval=>30,
42
+ # :healthy_threshold=>6,
43
+ # :unhealthy_threshold=>2},
44
+ # :instances=>["i-0941bf68", "i-a182d6c0"],
45
+ # :load_balancer_name=>"foo-lb",
46
+ # :app_cookie_stickiness_policies=>[],
47
+ # :lb_cookie_stickiness_policies=>[],
48
+ # :listeners=>
49
+ # [{:instance_port=>"80",
50
+ # :protocol=>"HTTP",
51
+ # :policy_names=>[],
52
+ # :load_balancer_port=>"80"}]}
@@ -0,0 +1,47 @@
1
+ class Description::RDS < Description
2
+ def initialize(description)
3
+ description[:service] ||= :rds
4
+ @description = description
5
+ end
6
+
7
+ def name
8
+ aws_id
9
+ end
10
+
11
+ def region_zone
12
+ availability_zone
13
+ end
14
+
15
+ def logical_zone
16
+ # parse from name if not multi_az, otherwise nil
17
+ super unless multi_az
18
+ end
19
+
20
+ end
21
+
22
+ # example rds description
23
+ # {:aws_id=>"foo-test-masterdb-1",
24
+ # :service => :rds, # this is set by maws
25
+ # :endpoint_port=>3306,
26
+ # :status=>"available",
27
+ # :multi_az=>true,
28
+ # :db_parameter_group=>{:status=>"in-sync", :name=>"default.mysql5.1"},
29
+ # :latest_restorable_time=>"2011-09-12T20:50:58.853Z",
30
+ # :master_username=>"root",
31
+ # :license_model=>"general-public-license",
32
+ # :engine=>"mysql",
33
+ # :pending_modified_values=>{},
34
+ # :db_security_groups=>[{:status=>"active", :name=>"default"}],
35
+ # :engine_version=>"5.1.57",
36
+ # :read_replica_db_instance_identifiers=>[],
37
+ # :availability_zone=>"us-east-1a",
38
+ # :backup_retention_period=>1,
39
+ # :create_time=>"2011-09-12T20:47:08.521Z",
40
+ # :auto_minor_version_upgrade=>true,
41
+ # :preferred_backup_window=>"07:30-08:00",
42
+ # :allocated_storage=>6,
43
+ # :instance_class=>"db.m1.small",
44
+ # :preferred_maintenance_window=>"mon:10:00-mon:10:30",
45
+ # :db_name=>"foo",
46
+ # :endpoint_address=>
47
+ # "foo-test-masterdb-1.ck6iyjop7iqg.us-east-1.rds.amazonaws.com"}
@@ -0,0 +1,78 @@
1
+ class Description
2
+ attr_reader :description
3
+
4
+ def self.create(description)
5
+ service = description[:service]
6
+ klass = Description.const_get("#{service.to_s.upcase}")
7
+ klass.new(description)
8
+ end
9
+
10
+ def [](key)
11
+ description[key]
12
+ end
13
+
14
+ def method_missing(method_name, *args, &block)
15
+ description[method_name.to_sym]
16
+ end
17
+
18
+ def initialize(description)
19
+ raise "use #{self.class}::create instead"
20
+ end
21
+
22
+ # logical zone (what the zone is according to maws categorization)
23
+ def zone
24
+ # us-east-1a => a
25
+ logical_zone
26
+ end
27
+
28
+ # zone where the instance really lives
29
+ # this has meaning for RDS with multi-zone = true and for EC2 with region scope
30
+ def physical_zone
31
+ region_zone[-1,1]
32
+ end
33
+
34
+ def region
35
+ # us-east-1a => us-east-1
36
+ region_zone[0...-1]
37
+ end
38
+
39
+ def name_re
40
+ /^(.+\.)?(.+)-(.+)-(\d+)(\w)?$/
41
+ end
42
+
43
+ def prefix
44
+ # old.foo-test-app-1z => old
45
+ md = name.match(name_re)
46
+ md[1].to_s[0...-1] if md
47
+ end
48
+
49
+ def profile
50
+ # foo-test-app-1z => foo-test
51
+ md = name.match(name_re)
52
+ md[2] if md
53
+ end
54
+
55
+ def role
56
+ md = name.match(name_re)
57
+ md[3] if md
58
+ end
59
+
60
+ def index
61
+ md = name.match(name_re)
62
+ md[4].to_i if md
63
+ end
64
+
65
+ def logical_zone
66
+ md = name.match(name_re)
67
+ md[5] if md
68
+ end
69
+
70
+ def create_instance(maws, config)
71
+ instance = Instance.create(maws, config, prefix, zone, role, index, {:service => service, :name => name, :region => region })
72
+ instance.description = self
73
+ instance
74
+ end
75
+ end
76
+
77
+ # load all description files
78
+ Dir.glob(File.dirname(__FILE__) + '/description/*.rb') {|file| require file}
@@ -0,0 +1,45 @@
1
+ require 'maws/instance'
2
+
3
+ # for EC2 instances aws_id is a random id
4
+ # name is a value of 'Name' tag
5
+ class Instance::EBS < Instance
6
+
7
+ def destroy
8
+ connection.ec2.delete_volume(aws_id)
9
+ info "destroying EBS volume #{name}:#{device} (#{aws_id})"
10
+ end
11
+
12
+ def attached?
13
+ aws_attachment_status == 'attached'
14
+ end
15
+
16
+ def attached_to_instance_id
17
+ return "" unless attached_instance_name
18
+ device[:aws_instance_id]
19
+ end
20
+
21
+ def display_fields
22
+ if attached?
23
+ super + [:device, :aws_id, :attachment_status, :aws_instance_id]
24
+ else
25
+ super + [:aws_id]
26
+ end
27
+ end
28
+
29
+ def service
30
+ :ebs
31
+ end
32
+
33
+ def physical_zone
34
+ super || @config.available_zones.first
35
+ end
36
+
37
+ def device
38
+ description.aws_device
39
+ end
40
+
41
+ def attachment_status
42
+ description.aws_attachment_status
43
+ end
44
+ end
45
+
@@ -0,0 +1,144 @@
1
+ require 'maws/instance'
2
+ require 'maws/ssh'
3
+
4
+ # for EC2 instances aws_id is a random id
5
+ # name is a value of 'Name' tag
6
+ class Instance::EC2 < Instance
7
+ def create
8
+ return if alive?
9
+ info "creating EC2 #{name}..."
10
+ image_id = config(:image_id) || connection.image_id_for_image_name(config(:image_name))
11
+ if image_id.nil?
12
+ info "no AMI id found with name '#{config(:image_name)}'"
13
+ return
14
+ end
15
+
16
+ results = connection.ec2.launch_instances(image_id,
17
+ :availability_zone => region_physical_zone,
18
+ :key_name => config(:keypair),
19
+ :min_count => 1,
20
+ :max_count => 1,
21
+ :group_names => security_groups,
22
+ :user_data => config(:user_data),
23
+ :monitoring_enabled => config(:monitoring_enabled),
24
+ :instance_type => config(:instance_type))
25
+
26
+
27
+ self.description = Description::EC2.new(results.first)
28
+ end
29
+
30
+ def set_prefix(prefix)
31
+ @prefix = prefix
32
+ old_name = @name
33
+ @name = self.class.name_for(@config, @prefix, @zone, @role, @index)
34
+
35
+ info "renaming #{old_name} to #{@name}"
36
+ create_tags
37
+ end
38
+
39
+ def create_tags
40
+ tag_instance_name
41
+ tag_volumes_names
42
+
43
+ info "...done (#{name} or #{aws_id} is ready)"
44
+ end
45
+
46
+ def tag_instance_name
47
+ retries_left = 20
48
+ loop do
49
+ begin
50
+ connection.ec2.create_tags(aws_id, {'Name' => name})
51
+ info "tagged EC2 instance #{aws_id} as #{name}"
52
+ return
53
+ rescue RightAws::AwsError => error
54
+ if error.message =~ /^InvalidInstanceID.NotFound/
55
+ info "TAGGING FAILED. RETRYING..."
56
+ else
57
+ raise error
58
+ end
59
+ end
60
+
61
+ retries_left -= 1
62
+ retries_left > 0 ? sleep(1) : break
63
+ end
64
+ error "Couldn't not tag #{aws_id} with name #{name}. It might not exist on AWS"
65
+ end
66
+
67
+ def tag_volumes_names
68
+ # wait a while before volume_ids are made available on the aws ec2 description
69
+ retries_left = 30
70
+ loop do
71
+ if volume_ids.count > 0
72
+ # tag and return
73
+ volume_ids.each {|vid|
74
+ connection.ec2.create_tags(vid, {'Name' => name})
75
+ info "tagged EBS volume #{vid} as #{name}"
76
+ }
77
+ return
78
+ end
79
+
80
+ # resync all descriptions (volume ids should appear if missing)
81
+ @maws.resync_instances
82
+
83
+ retries_left -= 1
84
+ retries_left > 0 ? sleep(1) : break
85
+ end
86
+ error "No volumes found for #{name} (#{aws_id})"
87
+ end
88
+
89
+ def destroy
90
+ return unless alive?
91
+ connection.ec2.terminate_instances(aws_id)
92
+ info "destroying EC2 #{name} (#{aws_id})"
93
+ end
94
+
95
+ def stop
96
+ return unless alive?
97
+ if status == 'running'
98
+ connection.ec2.stop_instances(aws_id)
99
+ info "stopping EC2 #{name} (#{aws_id})"
100
+ end
101
+ end
102
+
103
+ def start
104
+ return unless alive?
105
+ if status == 'stopped'
106
+ connection.ec2.start_instances(aws_id)
107
+ info "starting EC2 #{name} (#{aws_id})"
108
+ end
109
+ end
110
+
111
+ def ssh_available?
112
+ return false unless alive? && self.dns_name && !self.dns_name.empty?
113
+
114
+ begin
115
+ 3.times { # retry on host unreachable errors
116
+ begin
117
+ Net::SSH.start(dns_name, "phoneyuser", {:auth_methods => ["publickey"], :timeout => 1, :keys_only => true })
118
+ rescue Errno::EHOSTUNREACH
119
+ sleep 2
120
+ end
121
+ }
122
+ rescue Net::SSH::AuthenticationFailed
123
+ return true
124
+ rescue Object
125
+ return false
126
+ end
127
+ end
128
+
129
+ def volume_ids
130
+ description.ebs_volume_ids
131
+ end
132
+
133
+ def attached_volumes
134
+ description.attached_ebs_volume_ids
135
+ end
136
+
137
+ def service
138
+ :ec2
139
+ end
140
+
141
+ def display_fields
142
+ super + [:dns_name, :aws_instance_id, :aws_image_id]
143
+ end
144
+ end
@@ -0,0 +1,92 @@
1
+ require 'maws/instance'
2
+
3
+ # for ELBs aws_id is the same as their names
4
+ class Instance::ELB < Instance
5
+ def create
6
+ return if alive?
7
+ info "creating ELB #{name}..."
8
+
9
+ listeners = config(:listeners).dup || []
10
+
11
+ server = connection.elb.create_load_balancer(name, @connection.availability_zones, listeners)
12
+ connection.elb.configure_health_check(name, config(:health_check))
13
+
14
+ description = server ? {:load_balancer_name => name} : {}
15
+ sync_from_description(description)
16
+
17
+ info "...done (ELB #{name} is ready)\n\n"
18
+ end
19
+
20
+ def destroy
21
+ return unless alive?
22
+ connection.elb.delete_load_balancer(aws_id)
23
+ info "destroying ELB #{name}"
24
+ end
25
+
26
+ def add_instances(instances)
27
+ names = instances.map{|i| i.name}
28
+ info "adding instances to ELB #{aws_id}: #{names.join(', ')}"
29
+ connection.elb.register_instances_with_load_balancer(aws_id, instances.map{|i| i.aws_id})
30
+ info "...done"
31
+ end
32
+
33
+ def remove_instances(instances)
34
+ names = instances.map{|i| i.name}
35
+ info "removing instances to ELB #{aws_id}: #{names.join(', ')}"
36
+ connection.elb.deregister_instances_with_load_balancer(aws_id, instances.map{|i| i.aws_id})
37
+ info "...done"
38
+ end
39
+
40
+ def attached_instances
41
+ instance_ids = @aws_description[:instances]
42
+ @profile.defined_instances.select {|i| instance_ids.include?(i.aws_id)}
43
+ end
44
+
45
+ def enable_zones(zones)
46
+ full_zones = zones.map {|z| command_options.region + z}
47
+ info "enabling zones #{full_zones.join(', ')} for ELB #{aws_id}..."
48
+ connection.elb.enable_availability_zones_for_load_balancer(aws_id, full_zones)
49
+ info "...done"
50
+ end
51
+
52
+ def disable_zones(zones)
53
+ full_zones = zones.map {|z| command_options.region + z}
54
+ info "disabling zones #{full_zones.join(', ')} for ELB #{aws_id}"
55
+
56
+ if enabled_availability_zones.size <= 1
57
+ info "can't remove last remaining zone: #{enabled_availability_zones.first}"
58
+ return
59
+ end
60
+
61
+ connection.elb.disable_availability_zones_for_load_balancer(aws_id, full_zones)
62
+ info "...done"
63
+ end
64
+
65
+ def service
66
+ :elb
67
+ end
68
+
69
+ def physical_zone
70
+ nil
71
+ end
72
+
73
+ def enabled_availability_zones
74
+ description.availability_zones
75
+ end
76
+
77
+ def zones_list
78
+ (description.enabled_zones || []).join(', ')
79
+ end
80
+
81
+ def display_fields
82
+ [:name, :status, :zones_list, :first_listener_info]
83
+ end
84
+
85
+ def first_listener_info
86
+ return "" unless alive?
87
+ (description.listeners || [{}]).first.to_hash.collect do |key, val|
88
+ "#{key}=#{val}"
89
+ end.join("; ")
90
+ end
91
+
92
+ end