diff --git a/CHANGELOG.md b/CHANGELOG.md index fee0f33..4756935 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Cap-EC2 changelog +## 1.0.1 + +Added the possibility to get any tags defined on EC2 instance as parameters in Capistrano. +Updated AWS-SDK to Ver 2. + ## 1.0.0 Cap-EC2 is pretty stable, and the rate of PRs has decreased, so I've @@ -28,7 +33,7 @@ decided to bump the version to 1.0.0. ## 0.0.15 -* Add `ec2_filter_by_status_ok?` to filter out instances that aren't returning `OK` +* Add `ec2_filter_by_status_ok?` to filter out instances that aren't returning `OK` for their EC2 status checks. [@tomconroy](https://github.com/tomconroy) ## 0.0.14 diff --git a/cap-ec2.gemspec b/cap-ec2.gemspec index 94033d9..6665ee7 100644 --- a/cap-ec2.gemspec +++ b/cap-ec2.gemspec @@ -21,7 +21,9 @@ Gem::Specification.new do |spec| spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency "rake" + spec.add_dependency "aws-sdk" spec.add_dependency "aws-sdk-v1" + spec.add_dependency "aws-sdk-resources" spec.add_dependency "capistrano", ">= 3.0" spec.add_dependency "terminal-table" spec.add_dependency "colorize" diff --git a/lib/cap-ec2/capistrano.rb b/lib/cap-ec2/capistrano.rb index 9df98ce..3a10f78 100644 --- a/lib/cap-ec2/capistrano.rb +++ b/lib/cap-ec2/capistrano.rb @@ -20,8 +20,11 @@ def ec2_handler def ec2_role(name, options={}) ec2_handler.get_servers_for_role(name).each do |server| - env.role(name, CapEC2::Utils.contact_point(server), - options_with_instance_id(options, server)) + env.role( + name, + CapEC2::Utils.contact_point(server), + options_with_instance_id(options, server) + ) end end @@ -32,7 +35,10 @@ def env private def options_with_instance_id(options, server) - options.merge({aws_instance_id: server.instance_id}) + tags = server[:tag_set].map{ |t| Hash[t[0].downcase.to_sym, t[1]] }.reduce({}, :merge) + options.merge({ + aws_instance_id: server[:instance_id], + }).merge(tags) end end diff --git a/lib/cap-ec2/ec2-handler.rb b/lib/cap-ec2/ec2-handler.rb index 2d54887..cea19d9 100644 --- a/lib/cap-ec2/ec2-handler.rb +++ b/lib/cap-ec2/ec2-handler.rb @@ -13,7 +13,7 @@ def initialize def ec2_connect(region=nil) AWS.start_memoizing - AWS::EC2.new( + AWS::EC2::Client.new( access_key_id: fetch(:ec2_access_key_id), secret_access_key: fetch(:ec2_secret_access_key), region: region @@ -22,23 +22,23 @@ def ec2_connect(region=nil) def status_table CapEC2::StatusTable.new( - defined_roles.map {|r| get_servers_for_role(r)}.flatten.uniq {|i| i.instance_id} + defined_roles.map {|r| get_servers_for_role(r)}.flatten.uniq {|i| i[:instance_id]} ) end def server_names puts defined_roles.map {|r| get_servers_for_role(r)} .flatten - .uniq {|i| i.instance_id} - .map {|i| i.tags["Name"]} + .uniq {|i| i[:instance_id]} + .map {|i| i[:tag_set]["Name"] || i[:instance_id] + ' (Server name not specified)'} .join("\n") end def instance_ids puts defined_roles.map {|r| get_servers_for_role(r)} .flatten - .uniq {|i| i.instance_id} - .map {|i| i.instance_id} + .uniq {|i| i[:instance_id]} + .map {|i| i[:instance_id]} .join("\n") end @@ -60,18 +60,32 @@ def tag(tag_name) def get_servers_for_role(role) servers = [] + instances = [] + @ec2.each do |_, ec2| - instances = ec2.instances - .filter(tag(project_tag), "*#{application}*") - .filter('instance-state-name', 'running') - servers << instances.select do |i| + query = ec2.describe_instances(filters:[ + { name: 'instance-state-name', values: ["running"] }, + { name: "#{tag(project_tag)}", values: ["#{application}"] } + ]) + query[:reservation_set].each do |reservations| + reservations[:instances_set].each do |instance| + if instance[:tag_set][0] + instance[:tag_set].map!{|sm_h| Hash[sm_h[:key], sm_h[:value]]} + instance[:tag_set] = instance[:tag_set].reduce({}, :merge) + end + instances << instance + end + end + + servers = instances.select do |i| instance_has_tag?(i, roles_tag, role) && instance_has_tag?(i, stages_tag, stage) && instance_has_tag?(i, project_tag, application) && (fetch(:ec2_filter_by_status_ok?) ? instance_status_ok?(i) : true) end end - servers.flatten.sort_by {|s| s.tags["Name"] || ''} + + servers end def get_server(instance_id) @@ -83,15 +97,20 @@ def get_server(instance_id) private def instance_has_tag?(instance, key, value) - (instance.tags[key] || '').split(',').map(&:strip).include?(value.to_s) + (instance[:tag_set][key] || '').split(',').map(&:strip).include?(value.to_s) end def instance_status_ok?(instance) @ec2.any? do |_, ec2| - response = ec2.client.describe_instance_status( - instance_ids: [instance.id], - filters: [{ name: 'instance-status.status', values: %w(ok) }] - ) + response = ec2.describe_instance_status({ + instance_ids: [instance[:instance_id]], + filters: [ + { + name: 'instance-status.status', + values: %w(ok) + } + ] + }) response.data.has_key?(:instance_status_set) && response.data[:instance_status_set].any? end end diff --git a/lib/cap-ec2/status-table.rb b/lib/cap-ec2/status-table.rb index 6f338f7..ceaf419 100644 --- a/lib/cap-ec2/status-table.rb +++ b/lib/cap-ec2/status-table.rb @@ -1,12 +1,12 @@ module CapEC2 class StatusTable include CapEC2::Utils - + def initialize(instances) @instances = instances output end - + def header_row [ bold("Num"), @@ -19,7 +19,7 @@ def header_row bold("Stages") ] end - + def output table = Terminal::Table.new( :style => { @@ -38,13 +38,13 @@ def output def instance_to_row(instance, index) [ sprintf("%02d:", index), - green(instance.tags["Name"] || ''), - red(instance.id), - cyan(instance.instance_type), + green(instance[:tag_set]["Name"] || ''), + red(instance[:instance_id]), + cyan(instance[:instance_type]), bold(blue(CapEC2::Utils.contact_point(instance))), - magenta(instance.availability_zone), - yellow(instance.tags[roles_tag]), - yellow(instance.tags[stages_tag]) + magenta(instance[:placement][:availability_zone]), + yellow(instance[:tag_set][roles_tag]), + yellow(instance[:tag_set][stages_tag]) ] end diff --git a/lib/cap-ec2/utils.rb b/lib/cap-ec2/utils.rb index 9a18d9a..286c819 100644 --- a/lib/cap-ec2/utils.rb +++ b/lib/cap-ec2/utils.rb @@ -31,8 +31,7 @@ def self.contact_point_mapping def self.contact_point(instance) ec2_interface = contact_point_mapping[fetch(:ec2_contact_point)] return instance.send(ec2_interface) if ec2_interface - - instance.public_dns_name || instance.public_ip_address || instance.private_ip_address + instance[:dns_name] || instance[:ip_address] || instance[:private_ip_address] end def load_config