From d8b7ca66490606c5068cfe88a37d1da66906303e Mon Sep 17 00:00:00 2001 From: Travis Dempsey Date: Wed, 12 Dec 2012 22:31:37 -0600 Subject: [PATCH 01/14] added a --with-facet option to knife cluster list --- lib/chef/knife/cluster_list.rb | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/chef/knife/cluster_list.rb b/lib/chef/knife/cluster_list.rb index 3762f244..c75f84a5 100644 --- a/lib/chef/knife/cluster_list.rb +++ b/lib/chef/knife/cluster_list.rb @@ -27,23 +27,30 @@ class ClusterList < Knife require 'formatador' end - banner "knife cluster list (options)" - + banner 'knife cluster list (options)' + + option :facets, + :long => '--with-facets', + :description => 'List cluster facets along with names and paths', + :default => false, + :boolean => true + def run load_ironfan configure_dry_run - hash = Ironfan.cluster_filenames - - table = [] - hash.keys.sort.each do |key| - table.push( { :cluster => key, :path => hash[key] } ) + data = Ironfan.cluster_filenames.map do |name, path| + as_table = { :cluster => name, :path => path } + if config[:facets] + facets = Ironfan.load_cluster(name).facets.to_a.map(&:name).join(', ') + as_table.merge!(:facets => facets) + end + as_table end ui.info "Cluster Path: #{ Ironfan.cluster_path.join ", " }" - - Formatador.display_compact_table(table, [:cluster,:path]) - + headers = config[:facets] ? [:cluster, :facets, :path] : [:cluster, :path] + Formatador.display_compact_table(data, headers) end end end From 6e7195ad2f91a25923d1d49af56bfa77fcf19582 Mon Sep 17 00:00:00 2001 From: Nathaniel Eliot Date: Thu, 13 Dec 2012 10:54:02 -0600 Subject: [PATCH 02/14] Adding short option -f for knife cluster list --with-facet --- lib/chef/knife/cluster_list.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/chef/knife/cluster_list.rb b/lib/chef/knife/cluster_list.rb index c75f84a5..6c935419 100644 --- a/lib/chef/knife/cluster_list.rb +++ b/lib/chef/knife/cluster_list.rb @@ -31,6 +31,7 @@ class ClusterList < Knife option :facets, :long => '--with-facets', + :short => '-f', :description => 'List cluster facets along with names and paths', :default => false, :boolean => true From b20953fdc3854d784a00ecb7b691e111a34cf90d Mon Sep 17 00:00:00 2001 From: Nathaniel Eliot Date: Thu, 13 Dec 2012 11:03:53 -0600 Subject: [PATCH 03/14] Version bump to 4.6.2 --- CHANGELOG.md | 3 +++ VERSION | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a94f4761..e03f3b09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# v4.6.2: +* Added a -f/--with-facet option to knife cluster list + # v4.6.1: * Fixes nested array bug when computing list of AZs for an ELB (thanks @nickmarden) * Cleaning up overzealous Elastic IP inclusion (alternative fix to #222, thanks @nickmarden) diff --git a/VERSION b/VERSION index f4fa8fcb..3208b090 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.6.1 \ No newline at end of file +4.6.2 \ No newline at end of file From 4a6dc236bfbc74fdc51ba43387dc1a374d32a863 Mon Sep 17 00:00:00 2001 From: Nathaniel Eliot Date: Thu, 13 Dec 2012 11:04:51 -0600 Subject: [PATCH 04/14] Regenerate gemspec for version 4.6.2 --- ironfan.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ironfan.gemspec b/ironfan.gemspec index 57cb6ad0..1825a4ff 100644 --- a/ironfan.gemspec +++ b/ironfan.gemspec @@ -5,11 +5,11 @@ Gem::Specification.new do |s| s.name = "ironfan" - s.version = "4.6.1" + s.version = "4.6.2" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Infochimps"] - s.date = "2012-12-11" + s.date = "2012-12-13" s.description = "Ironfan allows you to orchestrate not just systems but clusters of machines. It includes a powerful layer on top of knife and a collection of cloud cookbooks." s.email = "coders@infochimps.com" s.extra_rdoc_files = [ From c9db847fb9f736c51643eed33171b2f1eb9c07bb Mon Sep 17 00:00:00 2001 From: Nick Marden Date: Thu, 13 Dec 2012 19:03:54 -0500 Subject: [PATCH 05/14] Added support for "prepare" phase, prior to any machine-specific actions --- lib/chef/knife/cluster_kill.rb | 4 ++++ lib/chef/knife/cluster_launch.rb | 5 +++++ lib/chef/knife/cluster_proxy.rb | 4 ++++ lib/chef/knife/cluster_sync.rb | 4 ++++ lib/chef/knife/ironfan_script.rb | 13 +++++++++++++ lib/ironfan/broker/computer.rb | 14 +++++++++++--- lib/ironfan/provider.rb | 11 +++++++++-- 7 files changed, 50 insertions(+), 5 deletions(-) diff --git a/lib/chef/knife/cluster_kill.rb b/lib/chef/knife/cluster_kill.rb index c05f7441..41a99d29 100644 --- a/lib/chef/knife/cluster_kill.rb +++ b/lib/chef/knife/cluster_kill.rb @@ -75,6 +75,10 @@ def confirm_execution(target) confirm_or_exit("Are you absolutely certain that you want to delete #{delete_message}? (Type 'Yes' to confirm) ", 'Yes') end + def prepares? + false + end + end end end diff --git a/lib/chef/knife/cluster_launch.rb b/lib/chef/knife/cluster_launch.rb index b6eabbd0..6dc28ecb 100644 --- a/lib/chef/knife/cluster_launch.rb +++ b/lib/chef/knife/cluster_launch.rb @@ -82,6 +82,11 @@ def run section("Syncing to chef") target.save :providers => :chef + unless target.empty? + ui.info "Preparing shared resources:" + all_computers(*@name_args).prepare + end + # Launch computers ui.info("") section("Launching computers", :green) diff --git a/lib/chef/knife/cluster_proxy.rb b/lib/chef/knife/cluster_proxy.rb index 892ea4b3..03151e8b 100644 --- a/lib/chef/knife/cluster_proxy.rb +++ b/lib/chef/knife/cluster_proxy.rb @@ -119,6 +119,10 @@ def proxy_pac_contents }\n} end + def prepares? + false + end + def aggregates? false end diff --git a/lib/chef/knife/cluster_sync.rb b/lib/chef/knife/cluster_sync.rb index beded71c..7e1a7f1b 100644 --- a/lib/chef/knife/cluster_sync.rb +++ b/lib/chef/knife/cluster_sync.rb @@ -62,6 +62,10 @@ def perform_execution(target) else Chef::Log.debug("Skipping sync to cloud") ; end end + def prepares_on_noop? + true + end + def aggregates_on_noop? true end diff --git a/lib/chef/knife/ironfan_script.rb b/lib/chef/knife/ironfan_script.rb index 17011527..af3252b5 100644 --- a/lib/chef/knife/ironfan_script.rb +++ b/lib/chef/knife/ironfan_script.rb @@ -44,6 +44,11 @@ def run target = get_relevant_slice(* @name_args) + if prepares? and (prepares_on_noop? or not target.empty?) + ui.info "Preparing shared resources:" + all_computers(*@name_args).prepare + end + unless target.empty? ui.info(["\n", ui.color("Running #{sub_command}", :cyan), @@ -76,6 +81,14 @@ def perform_execution(target) target.send(sub_command) end + def prepares? + true + end + + def prepares_on_noop? + false + end + def aggregates? true end diff --git a/lib/ironfan/broker/computer.rb b/lib/ironfan/broker/computer.rb index 68e6989b..b2398010 100644 --- a/lib/ironfan/broker/computer.rb +++ b/lib/ironfan/broker/computer.rb @@ -298,11 +298,19 @@ def validate values.map {|c| c.providers.values}.flatten.uniq.each {|p| p.validate computers } end - def aggregate + def group_action(verb) computers = self - provider_keys = values.map {|c| c.chosen_providers({ :providers => :iaas})}.flatten.uniq + provider_keys = values.map {|c| c.chosen_providers({ :providers => :iaas })}.flatten.uniq providers = provider_keys.map { |pk| values.map { |c| c.providers[pk] } }.flatten.compact.uniq - providers.each { |p| p.aggregate! computers } + providers.each { |p| p.send(verb, computers) } + end + + def prepare + group_action(:prepare!) + end + + def aggregate + group_action(:aggregate!) end # diff --git a/lib/ironfan/provider.rb b/lib/ironfan/provider.rb index 874a4f1e..d09545bd 100644 --- a/lib/ironfan/provider.rb +++ b/lib/ironfan/provider.rb @@ -42,6 +42,12 @@ def self.validate(computers) resources.each {|r| r.validate_resources! computers } end + def self.prepare!(computers) + resources.each do |r| + r.prepare!(computers) if r.shared? + end + end + def self.aggregate!(computers) resources.each do |r| r.aggregate!(computers) if r.shared? @@ -87,14 +93,15 @@ def on_correlate(*p) Ironfan.noop(self,__method__,*p); end # def self.create!(*p) Ironfan.noop(self,__method__,*p); end def self.save!(*p) Ironfan.noop(self,__method__,*p); end + def self.prepare!(*p) Ironfan.noop(self,__method__,*p); end def self.aggregate!(*p) Ironfan.noop(self,__method__,*p); end def self.destroy!(*p) Ironfan.noop(self,__method__,*p); end # # Utilities # - [:shared?, :multiple?, :load!,:validate_computer!, - :validate_resources!,:create!,:save!,:aggregate!,:destroy!].each do |method_name| + [:shared?, :multiple?, :load!,:validate_computer!, :validate_resources!, + :create!, :save!, :prepare!, :aggregate!, :destroy!].each do |method_name| define_method(method_name) {|*p| self.class.send(method_name,*p) } end From 78c281273cf626d2e744df6e7a8481afc8e3f179 Mon Sep 17 00:00:00 2001 From: Nick Marden Date: Thu, 13 Dec 2012 19:04:26 -0500 Subject: [PATCH 06/14] (fix #189) Move security group creation and authorization assurance to prepare phase --- lib/ironfan/provider/ec2/security_group.rb | 152 +++++++++++-------- spec/integration/spec/simple_cluster_spec.rb | 9 +- 2 files changed, 99 insertions(+), 62 deletions(-) diff --git a/lib/ironfan/provider/ec2/security_group.rb b/lib/ironfan/provider/ec2/security_group.rb index d1f9fe6a..85cca55f 100644 --- a/lib/ironfan/provider/ec2/security_group.rb +++ b/lib/ironfan/provider/ec2/security_group.rb @@ -20,22 +20,18 @@ def self.multiple?() true; end def self.resource_type() :security_group; end def self.expected_ids(computer) ec2 = computer.server.cloud(:ec2) - ec2.security_groups.keys.map do |name| - ec2.vpc ? "#{ec2.vpc}:#{name.to_s}" : name.to_s - end.uniq + ec2.security_groups.keys.map { |name| group_name_with_vpc(name,ec2.vpc) }.uniq end def name() - return adaptee.name if adaptee.vpc_id.nil? - "#{adaptee.vpc_id}:#{adaptee.name}" + self.class.group_name_with_vpc(adaptee.name, adaptee.vpc_id) end # # Discovery # def self.load!(cluster=nil) - Ec2.connection.security_groups.each do |raw| - next if raw.blank? + Ec2.connection.security_groups.reject { |raw| raw.blank? }.each do |raw| sg = SecurityGroup.new(:adaptee => raw) remember(sg) Chef::Log.debug("Loaded #{sg}: #{sg.inspect}") @@ -66,17 +62,73 @@ def to_s # Manipulation # - def self.create!(computer) - return unless Ec2.applicable computer - - ensure_groups(computer) - groups = self.expected_ids(computer) - # Only handle groups that don't already exist - groups.delete_if {|group| recall? group.to_s } - return if groups.empty? + def self.prepare!(computers) + + # Create any groups that don't yet exist, and ensure any authorizations + # that are required for those groups + cluster_name = nil + groups_to_create = [ ] + authorizations_to_ensure = [ ] + + # First, deduce the list of all groups to which at least one instance belongs + # We'll use this later to decide whether to create groups, or authorize access, + # using a VPC security group or an EC2 security group. + groups_that_should_exist = computers.map { |c| expected_ids(c) }.flatten.sort.uniq + groups_to_create << groups_that_should_exist + + computers.select { |computer| Ec2.applicable computer }.each do |computer| + ensure_groups(computer) # Add facet and cluster security groups for the computer + cloud = computer.server.cloud(:ec2) + cluster_name = computer.server.cluster_name + + # Iterate over all of the security group information, keeping track of + # any groups that must exist and any authorizations that must be ensured + cloud.security_groups.values.each do |dsl_group| + + groups_to_create << dsl_group.name + + groups_to_create << dsl_group.group_authorized.map do |other_group| + most_appropriate_group_name(other_group, cloud.vpc, groups_that_should_exist) + end + + groups_to_create << dsl_group.group_authorized_by.map do |other_group| + most_appropriate_group_name(other_group, cloud.vpc, groups_that_should_exist) + end + + authorizations_to_ensure << dsl_group.group_authorized.map do |other_group| + { + :grantor => most_appropriate_group_name(dsl_group.name, cloud.vpc, groups_that_should_exist), + :grantee => most_appropriate_group_name(other_group, cloud.vpc, groups_that_should_exist), + :grantee_type => :group, + :range => WIDE_OPEN, + } + end + + authorizations_to_ensure << dsl_group.group_authorized_by.map do |other_group| + { + :grantor => most_appropriate_group_name(other_group, cloud.vpc, groups_that_should_exist), + :grantee => most_appropriate_group_name(dsl_group.name, cloud.vpc, groups_that_should_exist), + :grantee_type => :group, + :range => WIDE_OPEN, + } + end + + authorizations_to_ensure << dsl_group.range_authorizations.map do |range_auth| + range, cidr, protocol = range_auth + { + :grantor => group_name_with_vpc(dsl_group.name, cloud.vpc), + :grantee => { :cidr_ip => cidr, :ip_protocol => protocol }, + :grantee_type => :cidr, + :range => range, + } + end + end + end + groups_to_create = groups_to_create.flatten.uniq.reject { |group| recall? group.to_s }.sort + authorizations_to_ensure = authorizations_to_ensure.flatten.uniq.sort { |a,b| a[:grantor] <=> b[:grantor] } - Ironfan.step(computer.server.cluster_name, "creating security groups", :blue) - groups.each do |group| + Ironfan.step(cluster_name, "creating security groups", :blue) unless groups_to_create.empty? + groups_to_create.each do |group| Ironfan.step(group, " creating #{group} security group", :blue) begin tokens = group.to_s.split(':') @@ -85,56 +137,34 @@ def self.create!(computer) Ec2.connection.create_security_group(group_id,"Ironfan created group #{group_id}",vpc_id) rescue Fog::Compute::AWS::Error => e # InvalidPermission.Duplicate Chef::Log.info("ignoring security group error: #{e}") - sleep 0.5 # quit racing so hard end end - load! # Get the native groups via reload - end - - def self.recall_with_vpc(name,vpc_id=nil) - group_name = vpc_id.nil? ? name : "#{vpc_id}:#{name}" - recall(group_name) - end - - def self.save!(computer) - return unless Ec2.applicable computer - cloud = computer.server.cloud(:ec2) - create!(computer) # Make sure the security groups exist - security_groups = cloud.security_groups.values - dsl_groups = security_groups.select do |dsl_group| - not (recall_with_vpc(dsl_group,cloud.vpc)) and \ - not (dsl_group.range_authorizations + - dsl_group.group_authorized_by + - dsl_group.group_authorized).empty? - end.compact - return if dsl_groups.empty? - - Ironfan.step(computer.server.cluster_name, "ensuring security group permissions", :blue) - dsl_groups.each do |dsl_group| - dsl_group_fog = recall_with_vpc(dsl_group.name,cloud.vpc) - dsl_group.group_authorized.each do |other_group| - other_group_fog = recall_with_vpc(other_group,cloud.vpc) - Ironfan.step(dsl_group.name, " ensuring access from #{other_group}", :blue) - options = {:group => other_group_fog.group_id} - safely_authorize(dsl_group_fog, WIDE_OPEN, options) + # Re-load everything so that we have a @@known list of security groups to manipulate + load! unless groups_to_create.empty? + + # Now make sure that all required authorizations are present + Ironfan.step(cluster_name, "ensuring security group permissions", :blue) unless authorizations_to_ensure.empty? + authorizations_to_ensure.each do |auth| + grantor_fog = recall(auth[:grantor]) + if :group == auth[:grantee_type] + options = { :group => recall(auth[:grantee]).group_id } + message = " ensuring access from #{auth[:grantee]} to #{auth[:grantor]}" + else + options = auth[:grantee] + message = " ensuring #{auth[:grantee][:ip_protocol]} access from #{auth[:grantee][:cidr_ip]} to #{auth[:range]}" end + Ironfan.step(auth[:grantor], message, :blue) + safely_authorize(grantor_fog, auth[:range], options) + end + end - dsl_group.group_authorized_by.each do |other_group| - other_group_fog = recall_with_vpc(other_group,cloud.vpc) - Ironfan.step(dsl_group.name, " ensuring access to #{other_group}", :blue) - options = {:group => dsl_group_fog.group_id} - safely_authorize(other_group_fog, WIDE_OPEN, options) - end + def self.group_name_with_vpc(name,vpc_id=nil) + vpc_id.nil? ? name.to_s : "#{vpc_id}:#{name.to_s}" + end - dsl_group.range_authorizations.each do |range_auth| - range, cidr, protocol = range_auth - step_message = " ensuring #{protocol} access from #{cidr} to #{range}" - Ironfan.step(dsl_group.name, step_message, :blue) - options = {:cidr_ip => cidr, :ip_protocol => protocol} - safely_authorize(dsl_group_fog, range, options) - end - end + def self.most_appropriate_group_name(group, vpc_id, all_valid_groups) + all_valid_groups.include?(group_name_with_vpc(group, vpc_id)) ? group_name_with_vpc(group, vpc_id) : group end # diff --git a/spec/integration/spec/simple_cluster_spec.rb b/spec/integration/spec/simple_cluster_spec.rb index 6786f785..7641f237 100644 --- a/spec/integration/spec/simple_cluster_spec.rb +++ b/spec/integration/spec/simple_cluster_spec.rb @@ -17,6 +17,7 @@ facet :web do instances 1 + cloud(:ec2).security_group(:web).authorize_group :web_clients end facet :db do @@ -35,7 +36,7 @@ describe "the web facet security groups" do subject { cluster.facets[:web].server(0).cloud(:ec2).security_groups.keys.map(&:to_s).sort } - it { should == %w[ simple simple-web ssh systemwide ] } + it { should == %w[ simple simple-web ssh systemwide web ] } end describe "the db facet security groups" do @@ -43,6 +44,12 @@ it { should == %w[ simple simple-db ssh systemwide ] } end + describe "the passively created security groups" do + it "should include the :web_clients group" do + Ironfan::Provider::Ec2::SecurityGroup.recall('web_clients').should_not be_nil + end + end + describe "the cluster-wide security group" do before :each do @sg = Ironfan::Provider::Ec2::SecurityGroup.recall('simple') From 67adc67f8e49fdcd88329157dce2ad703598bb13 Mon Sep 17 00:00:00 2001 From: Nick Marden Date: Thu, 13 Dec 2012 19:11:15 -0500 Subject: [PATCH 07/14] Move keypair creation to prepare phase --- lib/ironfan/provider/ec2/keypair.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ironfan/provider/ec2/keypair.rb b/lib/ironfan/provider/ec2/keypair.rb index e65e814a..94c14d4c 100644 --- a/lib/ironfan/provider/ec2/keypair.rb +++ b/lib/ironfan/provider/ec2/keypair.rb @@ -50,8 +50,9 @@ def receive_adaptee(obj) # Manipulation # - def self.create!(computer) - name = computer.server.cluster_name + def self.prepare!(computers) + return if computers.empty? + name = computers.values[0].server.cluster_name return if recall? name Ironfan.step(name, "creating key pair for #{name}", :blue) result = Ec2.connection.create_key_pair(name) From 2e6524d9c0fd54587f2cc4931fde38628b60e1e8 Mon Sep 17 00:00:00 2001 From: Nick Marden Date: Thu, 13 Dec 2012 19:24:04 -0500 Subject: [PATCH 08/14] (fix #207) Allow user/group-style security group references --- lib/ironfan/provider/ec2/security_group.rb | 49 +++++++++++++------- spec/integration/spec/simple_cluster_spec.rb | 15 +++++- 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/lib/ironfan/provider/ec2/security_group.rb b/lib/ironfan/provider/ec2/security_group.rb index 85cca55f..a6b25c13 100644 --- a/lib/ironfan/provider/ec2/security_group.rb +++ b/lib/ironfan/provider/ec2/security_group.rb @@ -129,14 +129,18 @@ def self.prepare!(computers) Ironfan.step(cluster_name, "creating security groups", :blue) unless groups_to_create.empty? groups_to_create.each do |group| - Ironfan.step(group, " creating #{group} security group", :blue) - begin - tokens = group.to_s.split(':') - group_id = tokens.pop - vpc_id = tokens.pop - Ec2.connection.create_security_group(group_id,"Ironfan created group #{group_id}",vpc_id) - rescue Fog::Compute::AWS::Error => e # InvalidPermission.Duplicate - Chef::Log.info("ignoring security group error: #{e}") + if group =~ /\// + Ironfan.step(group, " assuming that owner/group pair #{group} already exists", :blue) + else + Ironfan.step(group, " creating #{group} security group", :blue) + begin + tokens = group.to_s.split(':') + group_id = tokens.pop + vpc_id = tokens.pop + Ec2.connection.create_security_group(group_id,"Ironfan created group #{group_id}",vpc_id) + rescue Fog::Compute::AWS::Error => e # InvalidPermission.Duplicate + Chef::Log.info("ignoring security group error: #{e}") + end end end @@ -148,7 +152,13 @@ def self.prepare!(computers) authorizations_to_ensure.each do |auth| grantor_fog = recall(auth[:grantor]) if :group == auth[:grantee_type] - options = { :group => recall(auth[:grantee]).group_id } + if fog_grantee = recall(auth[:grantee]) + options = { :group => fog_grantee.group_id } + elsif auth[:grantee] =~ /\// + options = { :group_alias => auth[:grantee] } + else + raise "Don't know what to do with authorization grantee #{auth[:grantee]}" + end message = " ensuring access from #{auth[:grantee]} to #{auth[:grantor]}" else options = auth[:grantee] @@ -186,20 +196,27 @@ def self.ensure_groups(computer) # Try an authorization, ignoring duplicates (this is easier than correlating). # Do so for both TCP and UDP, unless only one is specified def self.safely_authorize(fog_group,range,options) - unless options[:ip_protocol] + if options[:group_alias] + owner, group = options[:group_alias].split(/\//) + self.patiently(fog_group.name, Fog::Compute::AWS::Error, :ignore => Proc.new { |e| e.message =~ /InvalidPermission\.Duplicate/ }) do + Ec2.connection.authorize_security_group_ingress( + 'GroupName' => fog_group.name, + 'SourceSecurityGroupName' => group, + 'SourceSecurityGroupOwnerId' => owner + ) + end + elsif options[:ip_protocol] + self.patiently(fog_group.name, Fog::Compute::AWS::Error, :ignore => Proc.new { |e| e.message =~ /InvalidPermission\.Duplicate/ }) do + fog_group.authorize_port_range(range,options) + end + else safely_authorize(fog_group,range,options.merge(:ip_protocol => 'tcp')) safely_authorize(fog_group,range,options.merge(:ip_protocol => 'udp')) safely_authorize(fog_group,Range.new(-1,-1),options.merge(:ip_protocol => 'icmp')) if(range == WIDE_OPEN) return end - - self.patiently(fog_group.name, Fog::Compute::AWS::Error, :ignore => Proc.new { |e| e.message =~ /InvalidPermission\.Duplicate/ }) do - fog_group.authorize_port_range(range,options) - end - end end - end end end diff --git a/spec/integration/spec/simple_cluster_spec.rb b/spec/integration/spec/simple_cluster_spec.rb index 7641f237..beae12b1 100644 --- a/spec/integration/spec/simple_cluster_spec.rb +++ b/spec/integration/spec/simple_cluster_spec.rb @@ -17,7 +17,10 @@ facet :web do instances 1 - cloud(:ec2).security_group(:web).authorize_group :web_clients + cloud(:ec2).security_group(:web) do + authorize_group :web_clients + authorize_group 'amazon-elb/amazon-elb-sg' + end end facet :db do @@ -83,7 +86,17 @@ @ordered_ipp['icmp']['fromPort'].to_i.should == -1 @ordered_ipp['icmp']['toPort'].to_i.should == -1 end + end + describe "the web security group" do + before :each do + @sg = Ironfan::Provider::Ec2::SecurityGroup.recall('web') + @ordered_ipp = Hash[ @sg.ip_permissions.map { |s| [ s['ipProtocol'], s ] } ] + end + + it "allows TCP connections to web_clients and to amazon-elb-sg" do + @ordered_ipp['tcp']['groups'].map { |g| g['groupName'] }.sort.should == %w[ amazon-elb-sg web_clients ] + end end end end From 52d8c63e00ee0fd8d327256cae39fb92b88bd23a Mon Sep 17 00:00:00 2001 From: Nathaniel Eliot Date: Fri, 14 Dec 2012 11:14:15 -0600 Subject: [PATCH 09/14] Version bump to 4.7.0 --- CHANGELOG.md | 7 +++++++ VERSION | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e03f3b09..fc16da97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# v4.7.0: +(@nickmarden rocks the house again) +* Added support for "prepare" phase, prior to any machine-specific actions +* Move security group creation and authorization assurance to prepare phase (fixes #189) +* Allow user/group-style security group references (fixes #207) +* Move keypair creation to prepare phase + # v4.6.2: * Added a -f/--with-facet option to knife cluster list diff --git a/VERSION b/VERSION index 3208b090..1163055e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.6.2 \ No newline at end of file +4.7.0 \ No newline at end of file From f947902f010ebf9260bc0c260873ff0f89a77b05 Mon Sep 17 00:00:00 2001 From: Nathaniel Eliot Date: Fri, 14 Dec 2012 11:14:26 -0600 Subject: [PATCH 10/14] Regenerate gemspec for version 4.7.0 --- ironfan.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ironfan.gemspec b/ironfan.gemspec index 1825a4ff..75e59039 100644 --- a/ironfan.gemspec +++ b/ironfan.gemspec @@ -5,11 +5,11 @@ Gem::Specification.new do |s| s.name = "ironfan" - s.version = "4.6.2" + s.version = "4.7.0" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Infochimps"] - s.date = "2012-12-13" + s.date = "2012-12-14" s.description = "Ironfan allows you to orchestrate not just systems but clusters of machines. It includes a powerful layer on top of knife and a collection of cloud cookbooks." s.email = "coders@infochimps.com" s.extra_rdoc_files = [ From 68eac16929d761e5d8dcaab8378a52b08f5a6189 Mon Sep 17 00:00:00 2001 From: Huston Hoburg Date: Thu, 20 Dec 2012 13:53:44 -0600 Subject: [PATCH 11/14] Fixes #227. Launched machines should announce their state as "started" --- lib/ironfan/broker/computer.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ironfan/broker/computer.rb b/lib/ironfan/broker/computer.rb index b2398010..a78ddcef 100644 --- a/lib/ironfan/broker/computer.rb +++ b/lib/ironfan/broker/computer.rb @@ -75,6 +75,7 @@ def kill(options={}) def launch ensure_dependencies iaas_provider.machine_class.create! self + node.announce_state :started save self end From 452a9369dbc99f98fef60871fa0acf00867be922 Mon Sep 17 00:00:00 2001 From: Nathaniel Eliot Date: Thu, 20 Dec 2012 16:03:08 -0600 Subject: [PATCH 12/14] Cleaning up omnibus usage to link embedded bin, ruby into default $PATHs, rather than use /etc/environment to try tweaking (doesn't hit a large number of programs) --- lib/chef/knife/bootstrap/ubuntu12.04-ironfan.erb | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/chef/knife/bootstrap/ubuntu12.04-ironfan.erb b/lib/chef/knife/bootstrap/ubuntu12.04-ironfan.erb index 191d5605..72acbd90 100644 --- a/lib/chef/knife/bootstrap/ubuntu12.04-ironfan.erb +++ b/lib/chef/knife/bootstrap/ubuntu12.04-ironfan.erb @@ -44,15 +44,12 @@ if [ ! -f /opt/chef/bin/chef-client ]; then curl -L http://www.opscode.com/chef/install.sh | sudo bash fi -# Include the omnibus' path in the system-wide path, to allow use of -# its executables (gem, ruby, bundler, etc.) -( -cat <<'EOP' -PATH="/opt/chef/embedded/bin/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games" -EOP -) >> /etc/environment -. /etc/environment +# Replace /usr/local/sbin with the omnibus' bin, to get it into the PATH +mv /usr/local/sbin{,~} +ln -s /opt/chef/embedded/bin /usr/local/sbin +# Link ruby into /usr/bin/ruby, to allow /usr/bin/env +ln -s /opt/chef/embedded/bin/ruby /usr/bin gem install extlib bundler json right_aws pry fog From 7fcab82c105c4832ddff0edf61e148586efe2688 Mon Sep 17 00:00:00 2001 From: Nathaniel Eliot Date: Thu, 20 Dec 2012 16:46:48 -0600 Subject: [PATCH 13/14] Version bump to 4.7.1 --- CHANGELOG.md | 4 ++++ VERSION | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc16da97..6b4941d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v4.7.1 +* Cleaning up omnibus usage to link embedded bin, ruby into default $PATHs, rather than use /etc/environment to try tweaking (doesn't hit a large number of programs) +* Launched machines should announce their state as "started" + # v4.7.0: (@nickmarden rocks the house again) * Added support for "prepare" phase, prior to any machine-specific actions diff --git a/VERSION b/VERSION index 1163055e..cfacfe40 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.7.0 \ No newline at end of file +4.7.1 \ No newline at end of file From 1a84a44e3d79fa7b1da898dc91c55db3eeac6b9e Mon Sep 17 00:00:00 2001 From: Nathaniel Eliot Date: Thu, 20 Dec 2012 16:50:05 -0600 Subject: [PATCH 14/14] Regenerate gemspec for version 4.7.1 --- ironfan.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ironfan.gemspec b/ironfan.gemspec index 75e59039..c8a963f7 100644 --- a/ironfan.gemspec +++ b/ironfan.gemspec @@ -5,11 +5,11 @@ Gem::Specification.new do |s| s.name = "ironfan" - s.version = "4.7.0" + s.version = "4.7.1" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Infochimps"] - s.date = "2012-12-14" + s.date = "2012-12-20" s.description = "Ironfan allows you to orchestrate not just systems but clusters of machines. It includes a powerful layer on top of knife and a collection of cloud cookbooks." s.email = "coders@infochimps.com" s.extra_rdoc_files = [