diff --git a/capify-ec2.gemspec b/capify-ec2.gemspec index ff04b05..767a6ec 100644 --- a/capify-ec2.gemspec +++ b/capify-ec2.gemspec @@ -19,7 +19,9 @@ Gem::Specification.new do |s| s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] - s.add_dependency('fog', '>= 1.23.0') + s.add_dependency('fog', '=1.23.0') + s.add_dependency('aws-sdk', '~> 3') s.add_dependency('colored', '=1.2') s.add_dependency('capistrano', '~> 2.14') + s.add_dependency('net-ssh', '=3.0.2') end diff --git a/lib/capify-ec2.rb b/lib/capify-ec2.rb index 1f7285e..43cf635 100644 --- a/lib/capify-ec2.rb +++ b/lib/capify-ec2.rb @@ -266,7 +266,6 @@ def get_load_balancer_by_name(load_balancer_name) lbs[load_balancer.id] = load_balancer end lbs[load_balancer_name] - end def deregister_instance_from_elb(instance_name) @@ -306,6 +305,34 @@ def register_instance_in_elb(instance_name, load_balancer_name = '') end end + def deregister_instance_from_named_elbs_by_dns(server_dns, load_balancer_names) + instance = get_instance_by_dns(server_dns) + + lbs = [] + threads = [] + + for load_balancer_name in load_balancer_names do + threads << Thread.new(load_balancer_name) do |lb| + load_balancer = get_load_balancer_by_name(lb) + + if load_balancer + puts "[Capify-EC2] Removing instance from named ELB '#{load_balancer.id}'..." + + result = elb.deregister_instances_from_load_balancer(instance.id, load_balancer.id) + raise "Unable to remove instance from ELB '#{load_balancer.id}'..." unless result.status == 200 + + lbs << load_balancer + end + end + end + + for t in threads do + t.join + end + + lbs + end + def deregister_instance_from_elb_by_dns(server_dns) instance = get_instance_by_dns(server_dns) load_balancer = get_load_balancer_by_instance(instance.id) @@ -316,7 +343,11 @@ def deregister_instance_from_elb_by_dns(server_dns) result = elb.deregister_instances_from_load_balancer(instance.id, load_balancer.id) raise "Unable to remove instance from ELB '#{load_balancer.id}'..." unless result.status == 200 - return load_balancer + #TODO: The ability to remove an instance from multiple ELBs has been added, which returns an [] of elbs. + #I've taken a shortcut here to return an array for this (the single ELB case). However, the correct solution + #would be to extend the above method to remove an instance from multiple ELBs by DNS too. + #This may break things for some users however? Needs to be checked. + return [load_balancer] end false end diff --git a/lib/capify-ec2/capistrano.rb b/lib/capify-ec2/capistrano.rb index b9ed26b..93609b7 100644 --- a/lib/capify-ec2/capistrano.rb +++ b/lib/capify-ec2/capistrano.rb @@ -121,19 +121,28 @@ def capify_ec2 roles.clear - load_balancer_to_reregister = nil # Set to nil again here, to ensure it always starts off nil for every iteration. + load_balancers_to_reregister = [] # Set to empty again here, to ensure it always starts off empty for every iteration. is_load_balanced = false + load_balancer_names = false server_roles.each do |a_role| role a_role, server_dns, all_options[a_role][server_dns] is_load_balanced = true if all_options[a_role][server_dns][:load_balanced] + + if all_options[a_role][server_dns][:elb_names] + load_balancer_names = all_options[a_role][server_dns][:elb_names] + end end puts "[Capify-EC2]" puts "[Capify-EC2] (#{index+1} of #{all_servers.length}) Beginning deployment to #{instance_dns_with_name_tag(server_dns)} with #{server_roles.count > 1 ? 'roles' : 'role'} '#{server_roles.join(', ')}'...".bold - unless dry_run - load_balancer_to_reregister = capify_ec2.deregister_instance_from_elb_by_dns(server_dns) if is_load_balanced + if is_load_balanced && !dry_run + if load_balancer_names + load_balancers_to_reregister = capify_ec2.deregister_instance_from_named_elbs_by_dns(server_dns, load_balancer_names) + else + load_balancers_to_reregister = capify_ec2.deregister_instance_from_elb_by_dns(server_dns) + end end # Call the standard 'cap deploy' task with our redefined role containing a single server. @@ -165,19 +174,28 @@ def capify_ec2 end end end - end - if load_balancer_to_reregister - reregistered = capify_ec2.reregister_instance_with_elb_by_dns(server_dns, load_balancer_to_reregister, 60) - if reregistered - puts "[Capify-EC2] Instance registration with ELB '#{load_balancer_to_reregister.id}' successful.".green.bold - else - puts "[Capify-EC2] Instance registration with ELB '#{load_balancer_to_reregister.id}' failed!".red.bold - raise CapifyEC2RollingDeployError.new("ELB registration timeout exceeded", server_dns) + threads = [] + + for load_balancer_to_reregister in load_balancers_to_reregister do + threads << Thread.new(load_balancer_to_reregister) do |lb| + puts "[Capify-EC2] Starting registration of ELB '#{lb.id}'" + + reregistered = capify_ec2.reregister_instance_with_elb_by_dns(server_dns, lb, 60) + if reregistered + puts "[Capify-EC2] Instance registration with ELB '#{lb.id}' successful.".green.bold + else + puts "[Capify-EC2] Instance registration with ELB '#{lb.id}' failed!".red.bold + raise CapifyEC2RollingDeployError.new("ELB registration timeout exceeded", server_dns) + end end end + for t in threads do + t.join + end + puts "[Capify-EC2] Deployment successful to #{instance_dns_with_name_tag(server_dns)}.".green.bold successful_deploys << server_dns @@ -327,4 +345,4 @@ def pluralise(n, singular, plural=nil) "#{singular}s" end end -end +end \ No newline at end of file diff --git a/readme.md b/readme.md index b0326f3..3c0f406 100644 --- a/readme.md +++ b/readme.md @@ -550,7 +550,20 @@ If an instance has been tagged with multiple roles, this behaviour will apply if If an instance is not associated with any ELBs, then the behaviour will be skipped silently, even if `:load_balanced` is set to 'true'. +If an instance belongs to multiple ELBs (e.g. a single instance pointed to by separate ELBs), you can force which ELBs are chosen by using the :elb_names parameter like this: +```ruby +ec2_roles :name => "web", + :variables => { + :healthcheck => { + :path => '/status', + :port => 80, + :result => 'OK' + } + :load_balanced => true, + :elb_names => ["the_name_of_your_elb", "the_name_of_another_elb"] + } +``` #### Viewing All Instances