ironfan 4.6.2 → 4.7.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.
- data/CHANGELOG.md +7 -0
- data/VERSION +1 -1
- data/ironfan.gemspec +2 -2
- data/lib/chef/knife/cluster_kill.rb +4 -0
- data/lib/chef/knife/cluster_launch.rb +5 -0
- data/lib/chef/knife/cluster_proxy.rb +4 -0
- data/lib/chef/knife/cluster_sync.rb +4 -0
- data/lib/chef/knife/ironfan_script.rb +13 -0
- data/lib/ironfan/broker/computer.rb +11 -3
- data/lib/ironfan/provider.rb +9 -2
- data/lib/ironfan/provider/ec2/keypair.rb +3 -2
- data/lib/ironfan/provider/ec2/security_group.rb +123 -76
- data/spec/integration/spec/simple_cluster_spec.rb +21 -1
- metadata +3 -3
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,10 @@ | |
| 1 | 
            +
            # v4.7.0:
         | 
| 2 | 
            +
            (@nickmarden rocks the house again)
         | 
| 3 | 
            +
            * Added support for "prepare" phase, prior to any machine-specific actions
         | 
| 4 | 
            +
            * Move security group creation and authorization assurance to prepare phase (fixes #189)
         | 
| 5 | 
            +
            * Allow user/group-style security group references (fixes #207)
         | 
| 6 | 
            +
            * Move keypair creation to prepare phase
         | 
| 7 | 
            +
             | 
| 1 8 | 
             
            # v4.6.2:
         | 
| 2 9 | 
             
            * Added a -f/--with-facet option to knife cluster list
         | 
| 3 10 |  | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            4. | 
| 1 | 
            +
            4.7.0
         | 
    
        data/ironfan.gemspec
    CHANGED
    
    | @@ -5,11 +5,11 @@ | |
| 5 5 |  | 
| 6 6 | 
             
            Gem::Specification.new do |s|
         | 
| 7 7 | 
             
              s.name = "ironfan"
         | 
| 8 | 
            -
              s.version = "4. | 
| 8 | 
            +
              s.version = "4.7.0"
         | 
| 9 9 |  | 
| 10 10 | 
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 11 11 | 
             
              s.authors = ["Infochimps"]
         | 
| 12 | 
            -
              s.date = "2012-12- | 
| 12 | 
            +
              s.date = "2012-12-14"
         | 
| 13 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."
         | 
| 14 14 | 
             
              s.email = "coders@infochimps.com"
         | 
| 15 15 | 
             
              s.extra_rdoc_files = [
         | 
| @@ -82,6 +82,11 @@ class Chef | |
| 82 82 | 
             
                    section("Syncing to chef")
         | 
| 83 83 | 
             
                    target.save :providers => :chef
         | 
| 84 84 |  | 
| 85 | 
            +
                    unless target.empty?
         | 
| 86 | 
            +
                      ui.info "Preparing shared resources:"
         | 
| 87 | 
            +
                      all_computers(*@name_args).prepare
         | 
| 88 | 
            +
                    end
         | 
| 89 | 
            +
             | 
| 85 90 | 
             
                    # Launch computers
         | 
| 86 91 | 
             
                    ui.info("")
         | 
| 87 92 | 
             
                    section("Launching computers", :green)
         | 
| @@ -44,6 +44,11 @@ module Ironfan | |
| 44 44 |  | 
| 45 45 | 
             
                  target = get_relevant_slice(* @name_args)
         | 
| 46 46 |  | 
| 47 | 
            +
                  if prepares? and (prepares_on_noop? or not target.empty?)
         | 
| 48 | 
            +
                    ui.info "Preparing shared resources:"
         | 
| 49 | 
            +
                    all_computers(*@name_args).prepare
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 47 52 | 
             
                  unless target.empty?
         | 
| 48 53 | 
             
                    ui.info(["\n",
         | 
| 49 54 | 
             
                             ui.color("Running #{sub_command}", :cyan),
         | 
| @@ -76,6 +81,14 @@ module Ironfan | |
| 76 81 | 
             
                  target.send(sub_command)
         | 
| 77 82 | 
             
                end
         | 
| 78 83 |  | 
| 84 | 
            +
                def prepares?
         | 
| 85 | 
            +
                  true
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                def prepares_on_noop?
         | 
| 89 | 
            +
                  false
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
             | 
| 79 92 | 
             
                def aggregates?
         | 
| 80 93 | 
             
                  true
         | 
| 81 94 | 
             
                end
         | 
| @@ -298,11 +298,19 @@ module Ironfan | |
| 298 298 | 
             
                    values.map {|c| c.providers.values}.flatten.uniq.each {|p| p.validate computers }
         | 
| 299 299 | 
             
                  end
         | 
| 300 300 |  | 
| 301 | 
            -
                  def  | 
| 301 | 
            +
                  def group_action(verb)
         | 
| 302 302 | 
             
                    computers = self
         | 
| 303 | 
            -
                    provider_keys = values.map {|c| c.chosen_providers({ :providers => :iaas})}.flatten.uniq
         | 
| 303 | 
            +
                    provider_keys = values.map {|c| c.chosen_providers({ :providers => :iaas })}.flatten.uniq
         | 
| 304 304 | 
             
                    providers     = provider_keys.map { |pk| values.map { |c| c.providers[pk] } }.flatten.compact.uniq
         | 
| 305 | 
            -
                    providers.each { |p| p. | 
| 305 | 
            +
                    providers.each { |p| p.send(verb, computers) }
         | 
| 306 | 
            +
                  end
         | 
| 307 | 
            +
             | 
| 308 | 
            +
                  def prepare
         | 
| 309 | 
            +
                    group_action(:prepare!)
         | 
| 310 | 
            +
                  end
         | 
| 311 | 
            +
             | 
| 312 | 
            +
                  def aggregate
         | 
| 313 | 
            +
                    group_action(:aggregate!)
         | 
| 306 314 | 
             
                  end
         | 
| 307 315 |  | 
| 308 316 | 
             
                  #
         | 
    
        data/lib/ironfan/provider.rb
    CHANGED
    
    | @@ -42,6 +42,12 @@ module Ironfan | |
| 42 42 | 
             
                  resources.each {|r| r.validate_resources! computers }
         | 
| 43 43 | 
             
                end
         | 
| 44 44 |  | 
| 45 | 
            +
                def self.prepare!(computers)
         | 
| 46 | 
            +
                  resources.each do |r|
         | 
| 47 | 
            +
                    r.prepare!(computers) if r.shared?
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 45 51 | 
             
                def self.aggregate!(computers)
         | 
| 46 52 | 
             
                  resources.each do |r|
         | 
| 47 53 | 
             
                    r.aggregate!(computers) if r.shared?
         | 
| @@ -87,14 +93,15 @@ module Ironfan | |
| 87 93 | 
             
                  #
         | 
| 88 94 | 
             
                  def self.create!(*p)              Ironfan.noop(self,__method__,*p);   end
         | 
| 89 95 | 
             
                  def self.save!(*p)                Ironfan.noop(self,__method__,*p);   end
         | 
| 96 | 
            +
                  def self.prepare!(*p)             Ironfan.noop(self,__method__,*p);   end
         | 
| 90 97 | 
             
                  def self.aggregate!(*p)           Ironfan.noop(self,__method__,*p);   end
         | 
| 91 98 | 
             
                  def self.destroy!(*p)             Ironfan.noop(self,__method__,*p);   end
         | 
| 92 99 |  | 
| 93 100 | 
             
                  #
         | 
| 94 101 | 
             
                  # Utilities
         | 
| 95 102 | 
             
                  #
         | 
| 96 | 
            -
                  [:shared?, :multiple?, :load!,:validate_computer!,
         | 
| 97 | 
            -
                   : | 
| 103 | 
            +
                  [:shared?, :multiple?, :load!,:validate_computer!, :validate_resources!,
         | 
| 104 | 
            +
                   :create!, :save!, :prepare!, :aggregate!, :destroy!].each do |method_name|
         | 
| 98 105 | 
             
                     define_method(method_name) {|*p| self.class.send(method_name,*p) }
         | 
| 99 106 | 
             
                   end
         | 
| 100 107 |  | 
| @@ -50,8 +50,9 @@ module Ironfan | |
| 50 50 | 
             
                    # Manipulation
         | 
| 51 51 | 
             
                    #
         | 
| 52 52 |  | 
| 53 | 
            -
                    def self. | 
| 54 | 
            -
                       | 
| 53 | 
            +
                    def self.prepare!(computers)
         | 
| 54 | 
            +
                      return if computers.empty?
         | 
| 55 | 
            +
                      name = computers.values[0].server.cluster_name
         | 
| 55 56 | 
             
                      return if recall? name
         | 
| 56 57 | 
             
                      Ironfan.step(name, "creating key pair for #{name}", :blue)
         | 
| 57 58 | 
             
                      result = Ec2.connection.create_key_pair(name)
         | 
| @@ -20,22 +20,18 @@ module Ironfan | |
| 20 20 | 
             
                    def self.resource_type()        :security_group;   end
         | 
| 21 21 | 
             
                    def self.expected_ids(computer)
         | 
| 22 22 | 
             
                      ec2 = computer.server.cloud(:ec2)
         | 
| 23 | 
            -
                      ec2.security_groups.keys.map  | 
| 24 | 
            -
                        ec2.vpc ? "#{ec2.vpc}:#{name.to_s}" : name.to_s
         | 
| 25 | 
            -
                      end.uniq
         | 
| 23 | 
            +
                      ec2.security_groups.keys.map { |name| group_name_with_vpc(name,ec2.vpc) }.uniq
         | 
| 26 24 | 
             
                    end
         | 
| 27 25 |  | 
| 28 26 | 
             
                    def name()
         | 
| 29 | 
            -
                       | 
| 30 | 
            -
                      "#{adaptee.vpc_id}:#{adaptee.name}"
         | 
| 27 | 
            +
                      self.class.group_name_with_vpc(adaptee.name, adaptee.vpc_id)
         | 
| 31 28 | 
             
                    end
         | 
| 32 29 |  | 
| 33 30 | 
             
                    #
         | 
| 34 31 | 
             
                    # Discovery
         | 
| 35 32 | 
             
                    #
         | 
| 36 33 | 
             
                    def self.load!(cluster=nil)
         | 
| 37 | 
            -
                      Ec2.connection.security_groups.each do |raw|
         | 
| 38 | 
            -
                        next if raw.blank?
         | 
| 34 | 
            +
                      Ec2.connection.security_groups.reject { |raw| raw.blank? }.each do |raw|
         | 
| 39 35 | 
             
                        sg = SecurityGroup.new(:adaptee => raw)
         | 
| 40 36 | 
             
                        remember(sg)
         | 
| 41 37 | 
             
                        Chef::Log.debug("Loaded #{sg}: #{sg.inspect}")
         | 
| @@ -66,75 +62,119 @@ module Ironfan | |
| 66 62 | 
             
                    # Manipulation
         | 
| 67 63 | 
             
                    #
         | 
| 68 64 |  | 
| 69 | 
            -
                    def self. | 
| 70 | 
            -
             | 
| 65 | 
            +
                    def self.prepare!(computers)
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                      # Create any groups that don't yet exist, and ensure any authorizations
         | 
| 68 | 
            +
                      # that are required for those groups
         | 
| 69 | 
            +
                      cluster_name             = nil
         | 
| 70 | 
            +
                      groups_to_create         = [ ]
         | 
| 71 | 
            +
                      authorizations_to_ensure = [ ]
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                      # First, deduce the list of all groups to which at least one instance belongs
         | 
| 74 | 
            +
                      # We'll use this later to decide whether to create groups, or authorize access,
         | 
| 75 | 
            +
                      # using a VPC security group or an EC2 security group.
         | 
| 76 | 
            +
                      groups_that_should_exist = computers.map { |c| expected_ids(c) }.flatten.sort.uniq
         | 
| 77 | 
            +
                      groups_to_create << groups_that_should_exist
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                      computers.select { |computer| Ec2.applicable computer }.each do |computer|
         | 
| 80 | 
            +
                        ensure_groups(computer) # Add facet and cluster security groups for the computer
         | 
| 81 | 
            +
                        cloud           = computer.server.cloud(:ec2)
         | 
| 82 | 
            +
                        cluster_name    = computer.server.cluster_name
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                        # Iterate over all of the security group information, keeping track of
         | 
| 85 | 
            +
                        # any groups that must exist and any authorizations that must be ensured
         | 
| 86 | 
            +
                        cloud.security_groups.values.each do |dsl_group|
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                          groups_to_create << dsl_group.name
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                          groups_to_create << dsl_group.group_authorized.map do |other_group|
         | 
| 91 | 
            +
                            most_appropriate_group_name(other_group, cloud.vpc, groups_that_should_exist)
         | 
| 92 | 
            +
                          end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                          groups_to_create << dsl_group.group_authorized_by.map do |other_group|
         | 
| 95 | 
            +
                            most_appropriate_group_name(other_group, cloud.vpc, groups_that_should_exist)
         | 
| 96 | 
            +
                          end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                          authorizations_to_ensure << dsl_group.group_authorized.map do |other_group|
         | 
| 99 | 
            +
                            {
         | 
| 100 | 
            +
                              :grantor      => most_appropriate_group_name(dsl_group.name, cloud.vpc, groups_that_should_exist),
         | 
| 101 | 
            +
                              :grantee      => most_appropriate_group_name(other_group, cloud.vpc, groups_that_should_exist),
         | 
| 102 | 
            +
                              :grantee_type => :group,
         | 
| 103 | 
            +
                              :range        => WIDE_OPEN,
         | 
| 104 | 
            +
                            }
         | 
| 105 | 
            +
                          end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                          authorizations_to_ensure << dsl_group.group_authorized_by.map do |other_group|
         | 
| 108 | 
            +
                            {
         | 
| 109 | 
            +
                              :grantor      => most_appropriate_group_name(other_group, cloud.vpc, groups_that_should_exist),
         | 
| 110 | 
            +
                              :grantee      => most_appropriate_group_name(dsl_group.name, cloud.vpc, groups_that_should_exist),
         | 
| 111 | 
            +
                              :grantee_type => :group,
         | 
| 112 | 
            +
                              :range        => WIDE_OPEN,
         | 
| 113 | 
            +
                            }
         | 
| 114 | 
            +
                          end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                          authorizations_to_ensure << dsl_group.range_authorizations.map do |range_auth|
         | 
| 117 | 
            +
                            range, cidr, protocol = range_auth
         | 
| 118 | 
            +
                            {
         | 
| 119 | 
            +
                              :grantor      => group_name_with_vpc(dsl_group.name, cloud.vpc),
         | 
| 120 | 
            +
                              :grantee      => { :cidr_ip => cidr, :ip_protocol => protocol },
         | 
| 121 | 
            +
                              :grantee_type => :cidr,
         | 
| 122 | 
            +
                              :range        => range,
         | 
| 123 | 
            +
                            }
         | 
| 124 | 
            +
                          end
         | 
| 125 | 
            +
                        end
         | 
| 126 | 
            +
                      end
         | 
| 127 | 
            +
                      groups_to_create         = groups_to_create.flatten.uniq.reject { |group| recall? group.to_s }.sort
         | 
| 128 | 
            +
                      authorizations_to_ensure = authorizations_to_ensure.flatten.uniq.sort { |a,b| a[:grantor] <=> b[:grantor] }
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                      Ironfan.step(cluster_name, "creating security groups", :blue) unless groups_to_create.empty?
         | 
| 131 | 
            +
                      groups_to_create.each do |group|
         | 
| 132 | 
            +
                        if group =~ /\//
         | 
| 133 | 
            +
                          Ironfan.step(group, "  assuming that owner/group pair #{group} already exists", :blue)
         | 
| 134 | 
            +
                        else
         | 
| 135 | 
            +
                          Ironfan.step(group, "  creating #{group} security group", :blue)
         | 
| 136 | 
            +
                          begin
         | 
| 137 | 
            +
                            tokens    = group.to_s.split(':')
         | 
| 138 | 
            +
                            group_id  = tokens.pop
         | 
| 139 | 
            +
                            vpc_id    = tokens.pop
         | 
| 140 | 
            +
                            Ec2.connection.create_security_group(group_id,"Ironfan created group #{group_id}",vpc_id)
         | 
| 141 | 
            +
                          rescue Fog::Compute::AWS::Error => e # InvalidPermission.Duplicate
         | 
| 142 | 
            +
                            Chef::Log.info("ignoring security group error: #{e}")
         | 
| 143 | 
            +
                          end
         | 
| 144 | 
            +
                        end
         | 
| 145 | 
            +
                      end
         | 
| 71 146 |  | 
| 72 | 
            -
                       | 
| 73 | 
            -
                       | 
| 74 | 
            -
             | 
| 75 | 
            -
                       | 
| 76 | 
            -
                       | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
                           | 
| 83 | 
            -
             | 
| 84 | 
            -
                           | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 87 | 
            -
                           | 
| 88 | 
            -
             | 
| 147 | 
            +
                      # Re-load everything so that we have a @@known list of security groups to manipulate
         | 
| 148 | 
            +
                      load! unless groups_to_create.empty?
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                      # Now make sure that all required authorizations are present
         | 
| 151 | 
            +
                      Ironfan.step(cluster_name, "ensuring security group permissions", :blue) unless authorizations_to_ensure.empty?
         | 
| 152 | 
            +
                      authorizations_to_ensure.each do |auth|
         | 
| 153 | 
            +
                        grantor_fog = recall(auth[:grantor])
         | 
| 154 | 
            +
                        if :group == auth[:grantee_type]
         | 
| 155 | 
            +
                          if fog_grantee = recall(auth[:grantee])
         | 
| 156 | 
            +
                            options = { :group => fog_grantee.group_id }
         | 
| 157 | 
            +
                          elsif auth[:grantee] =~ /\//
         | 
| 158 | 
            +
                            options = { :group_alias => auth[:grantee] }
         | 
| 159 | 
            +
                          else
         | 
| 160 | 
            +
                            raise "Don't know what to do with authorization grantee #{auth[:grantee]}"
         | 
| 161 | 
            +
                          end
         | 
| 162 | 
            +
                          message = "  ensuring access from #{auth[:grantee]} to #{auth[:grantor]}"
         | 
| 163 | 
            +
                        else
         | 
| 164 | 
            +
                          options = auth[:grantee]
         | 
| 165 | 
            +
                          message = "  ensuring #{auth[:grantee][:ip_protocol]} access from #{auth[:grantee][:cidr_ip]} to #{auth[:range]}"
         | 
| 89 166 | 
             
                        end
         | 
| 167 | 
            +
                        Ironfan.step(auth[:grantor], message, :blue)
         | 
| 168 | 
            +
                        safely_authorize(grantor_fog, auth[:range], options)
         | 
| 90 169 | 
             
                      end
         | 
| 91 | 
            -
                      load! # Get the native groups via reload
         | 
| 92 170 | 
             
                    end
         | 
| 93 171 |  | 
| 94 | 
            -
                    def self. | 
| 95 | 
            -
                       | 
| 96 | 
            -
                      recall(group_name)
         | 
| 172 | 
            +
                    def self.group_name_with_vpc(name,vpc_id=nil)
         | 
| 173 | 
            +
                      vpc_id.nil? ? name.to_s : "#{vpc_id}:#{name.to_s}"
         | 
| 97 174 | 
             
                    end
         | 
| 98 175 |  | 
| 99 | 
            -
                    def self. | 
| 100 | 
            -
                       | 
| 101 | 
            -
                      cloud = computer.server.cloud(:ec2)
         | 
| 102 | 
            -
             | 
| 103 | 
            -
                      create!(computer)            # Make sure the security groups exist
         | 
| 104 | 
            -
                      security_groups = cloud.security_groups.values
         | 
| 105 | 
            -
                      dsl_groups = security_groups.select do |dsl_group|
         | 
| 106 | 
            -
                        not (recall_with_vpc(dsl_group,cloud.vpc)) and \
         | 
| 107 | 
            -
                        not (dsl_group.range_authorizations +
         | 
| 108 | 
            -
                             dsl_group.group_authorized_by +
         | 
| 109 | 
            -
                             dsl_group.group_authorized).empty?
         | 
| 110 | 
            -
                      end.compact
         | 
| 111 | 
            -
                      return if dsl_groups.empty?
         | 
| 112 | 
            -
             | 
| 113 | 
            -
                      Ironfan.step(computer.server.cluster_name, "ensuring security group permissions", :blue)
         | 
| 114 | 
            -
                      dsl_groups.each do |dsl_group|
         | 
| 115 | 
            -
                        dsl_group_fog = recall_with_vpc(dsl_group.name,cloud.vpc)
         | 
| 116 | 
            -
                        dsl_group.group_authorized.each do |other_group|
         | 
| 117 | 
            -
                          other_group_fog = recall_with_vpc(other_group,cloud.vpc)
         | 
| 118 | 
            -
                          Ironfan.step(dsl_group.name, "  ensuring access from #{other_group}", :blue)
         | 
| 119 | 
            -
                          options = {:group => other_group_fog.group_id}
         | 
| 120 | 
            -
                          safely_authorize(dsl_group_fog, WIDE_OPEN, options)
         | 
| 121 | 
            -
                        end
         | 
| 122 | 
            -
             | 
| 123 | 
            -
                        dsl_group.group_authorized_by.each do |other_group|
         | 
| 124 | 
            -
                          other_group_fog = recall_with_vpc(other_group,cloud.vpc)
         | 
| 125 | 
            -
                          Ironfan.step(dsl_group.name, "  ensuring access to #{other_group}", :blue)
         | 
| 126 | 
            -
                          options = {:group => dsl_group_fog.group_id}
         | 
| 127 | 
            -
                          safely_authorize(other_group_fog, WIDE_OPEN, options)
         | 
| 128 | 
            -
                        end
         | 
| 129 | 
            -
             | 
| 130 | 
            -
                        dsl_group.range_authorizations.each do |range_auth|
         | 
| 131 | 
            -
                          range, cidr, protocol = range_auth
         | 
| 132 | 
            -
                          step_message = "  ensuring #{protocol} access from #{cidr} to #{range}"
         | 
| 133 | 
            -
                          Ironfan.step(dsl_group.name, step_message, :blue)
         | 
| 134 | 
            -
                          options = {:cidr_ip => cidr, :ip_protocol => protocol}
         | 
| 135 | 
            -
                          safely_authorize(dsl_group_fog, range, options)
         | 
| 136 | 
            -
                        end
         | 
| 137 | 
            -
                      end
         | 
| 176 | 
            +
                    def self.most_appropriate_group_name(group, vpc_id, all_valid_groups)
         | 
| 177 | 
            +
                      all_valid_groups.include?(group_name_with_vpc(group, vpc_id)) ? group_name_with_vpc(group, vpc_id) : group
         | 
| 138 178 | 
             
                    end
         | 
| 139 179 |  | 
| 140 180 | 
             
                    #
         | 
| @@ -156,20 +196,27 @@ module Ironfan | |
| 156 196 | 
             
                    # Try an authorization, ignoring duplicates (this is easier than correlating).
         | 
| 157 197 | 
             
                    # Do so for both TCP and UDP, unless only one is specified
         | 
| 158 198 | 
             
                    def self.safely_authorize(fog_group,range,options)
         | 
| 159 | 
            -
                       | 
| 199 | 
            +
                      if options[:group_alias]
         | 
| 200 | 
            +
                        owner, group = options[:group_alias].split(/\//)
         | 
| 201 | 
            +
                        self.patiently(fog_group.name, Fog::Compute::AWS::Error, :ignore => Proc.new { |e| e.message =~ /InvalidPermission\.Duplicate/ }) do
         | 
| 202 | 
            +
                          Ec2.connection.authorize_security_group_ingress(
         | 
| 203 | 
            +
                            'GroupName'                   => fog_group.name,
         | 
| 204 | 
            +
                            'SourceSecurityGroupName'     => group,
         | 
| 205 | 
            +
                            'SourceSecurityGroupOwnerId'  => owner
         | 
| 206 | 
            +
                          )
         | 
| 207 | 
            +
                        end
         | 
| 208 | 
            +
                      elsif options[:ip_protocol]
         | 
| 209 | 
            +
                        self.patiently(fog_group.name, Fog::Compute::AWS::Error, :ignore => Proc.new { |e| e.message =~ /InvalidPermission\.Duplicate/ }) do
         | 
| 210 | 
            +
                          fog_group.authorize_port_range(range,options)
         | 
| 211 | 
            +
                        end
         | 
| 212 | 
            +
                      else
         | 
| 160 213 | 
             
                        safely_authorize(fog_group,range,options.merge(:ip_protocol => 'tcp'))
         | 
| 161 214 | 
             
                        safely_authorize(fog_group,range,options.merge(:ip_protocol => 'udp'))
         | 
| 162 215 | 
             
                        safely_authorize(fog_group,Range.new(-1,-1),options.merge(:ip_protocol => 'icmp')) if(range == WIDE_OPEN)
         | 
| 163 216 | 
             
                        return
         | 
| 164 217 | 
             
                      end
         | 
| 165 | 
            -
             | 
| 166 | 
            -
                      self.patiently(fog_group.name, Fog::Compute::AWS::Error, :ignore => Proc.new { |e| e.message =~ /InvalidPermission\.Duplicate/ }) do
         | 
| 167 | 
            -
                        fog_group.authorize_port_range(range,options)
         | 
| 168 | 
            -
                      end
         | 
| 169 | 
            -
             | 
| 170 218 | 
             
                    end
         | 
| 171 219 | 
             
                  end
         | 
| 172 | 
            -
             | 
| 173 220 | 
             
                end
         | 
| 174 221 | 
             
              end
         | 
| 175 222 | 
             
            end
         | 
| @@ -17,6 +17,10 @@ Ironfan.cluster "simple" do | |
| 17 17 |  | 
| 18 18 | 
             
              facet :web do
         | 
| 19 19 | 
             
                instances 1
         | 
| 20 | 
            +
                cloud(:ec2).security_group(:web) do
         | 
| 21 | 
            +
                  authorize_group :web_clients
         | 
| 22 | 
            +
                  authorize_group 'amazon-elb/amazon-elb-sg'
         | 
| 23 | 
            +
                end
         | 
| 20 24 | 
             
              end
         | 
| 21 25 |  | 
| 22 26 | 
             
              facet :db do
         | 
| @@ -35,7 +39,7 @@ launch_cluster 'simple' do |cluster, computers| | |
| 35 39 |  | 
| 36 40 | 
             
                describe "the web facet security groups" do
         | 
| 37 41 | 
             
                  subject { cluster.facets[:web].server(0).cloud(:ec2).security_groups.keys.map(&:to_s).sort }
         | 
| 38 | 
            -
                  it { should == %w[ simple simple-web ssh systemwide ] }
         | 
| 42 | 
            +
                  it { should == %w[ simple simple-web ssh systemwide web ] }
         | 
| 39 43 | 
             
                end
         | 
| 40 44 |  | 
| 41 45 | 
             
                describe "the db facet security groups" do
         | 
| @@ -43,6 +47,12 @@ launch_cluster 'simple' do |cluster, computers| | |
| 43 47 | 
             
                  it { should == %w[ simple simple-db ssh systemwide ] }
         | 
| 44 48 | 
             
                end
         | 
| 45 49 |  | 
| 50 | 
            +
                describe "the passively created security groups" do
         | 
| 51 | 
            +
                  it "should include the :web_clients group" do
         | 
| 52 | 
            +
                    Ironfan::Provider::Ec2::SecurityGroup.recall('web_clients').should_not be_nil
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 46 56 | 
             
                describe "the cluster-wide security group" do
         | 
| 47 57 | 
             
                  before :each do
         | 
| 48 58 | 
             
                    @sg = Ironfan::Provider::Ec2::SecurityGroup.recall('simple')
         | 
| @@ -76,7 +86,17 @@ launch_cluster 'simple' do |cluster, computers| | |
| 76 86 | 
             
                    @ordered_ipp['icmp']['fromPort'].to_i.should              == -1
         | 
| 77 87 | 
             
                    @ordered_ipp['icmp']['toPort'].to_i.should                == -1
         | 
| 78 88 | 
             
                  end
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                describe "the web security group" do
         | 
| 92 | 
            +
                  before :each do
         | 
| 93 | 
            +
                    @sg = Ironfan::Provider::Ec2::SecurityGroup.recall('web')
         | 
| 94 | 
            +
                    @ordered_ipp = Hash[ @sg.ip_permissions.map { |s| [ s['ipProtocol'], s ] } ]
         | 
| 95 | 
            +
                  end
         | 
| 79 96 |  | 
| 97 | 
            +
                  it "allows TCP connections to web_clients and to amazon-elb-sg" do
         | 
| 98 | 
            +
                    @ordered_ipp['tcp']['groups'].map { |g| g['groupName'] }.sort.should == %w[ amazon-elb-sg web_clients ]
         | 
| 99 | 
            +
                  end
         | 
| 80 100 | 
             
                end
         | 
| 81 101 | 
             
              end
         | 
| 82 102 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -2,7 +2,7 @@ | |
| 2 2 | 
             
            name: ironfan
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 4 | 
             
              prerelease: 
         | 
| 5 | 
            -
              version: 4. | 
| 5 | 
            +
              version: 4.7.0
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors: 
         | 
| 8 8 | 
             
            - Infochimps
         | 
| @@ -10,7 +10,7 @@ autorequire: | |
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 12 |  | 
| 13 | 
            -
            date: 2012-12- | 
| 13 | 
            +
            date: 2012-12-14 00:00:00 Z
         | 
| 14 14 | 
             
            dependencies: 
         | 
| 15 15 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 16 16 | 
             
              name: chef
         | 
| @@ -282,7 +282,7 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 282 282 | 
             
              requirements: 
         | 
| 283 283 | 
             
              - - ">="
         | 
| 284 284 | 
             
                - !ruby/object:Gem::Version 
         | 
| 285 | 
            -
                  hash:  | 
| 285 | 
            +
                  hash: -2214564911911745674
         | 
| 286 286 | 
             
                  segments: 
         | 
| 287 287 | 
             
                  - 0
         | 
| 288 288 | 
             
                  version: "0"
         |