ironfan 4.2.0 → 4.2.1

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 CHANGED
@@ -1,3 +1,13 @@
1
+ # v4.2.1: @nickmarden rocks the house
2
+ * More correct merging of cluster and facet objects, with specs
3
+ * Circumvent memory bloat by resolving just once
4
+
5
+ # v4.2.0:
6
+ * providers now load in parallel
7
+ * substeps announcements for load are now done in provider, not individual resources
8
+ * only dump computers full information on -VV
9
+ * more cleanup of new specs
10
+
1
11
  # v4.1.1: fixing 'rake spec'
2
12
  * Remove all defunct tests and start fresh (fixes #137)
3
13
  * Failing spec for #158
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.2.0
1
+ 4.2.1
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.2.0"
8
+ s.version = "4.2.1"
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-09-29"
12
+ s.date = "2012-10-01"
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 = [
@@ -85,6 +85,7 @@ Gem::Specification.new do |s|
85
85
  "lib/ironfan/provider/virtualbox/machine.rb",
86
86
  "lib/ironfan/requirements.rb",
87
87
  "spec/ironfan/cluster_spec.rb",
88
+ "spec/ironfan/ec2/cloud_provider_spec.rb",
88
89
  "spec/ironfan/ec2/security_group_spec.rb",
89
90
  "spec/spec_helper.rb",
90
91
  "spec/spec_helper/dummy_chef.rb",
@@ -96,7 +97,7 @@ Gem::Specification.new do |s|
96
97
  s.require_paths = ["lib"]
97
98
  s.rubygems_version = "1.8.24"
98
99
  s.summary = "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."
99
- s.test_files = ["spec/spec_helper/dummy_chef.rb", "spec/ironfan/cluster_spec.rb", "spec/ironfan/ec2/security_group_spec.rb", "spec/spec_helper.rb", "spec/test_config.rb"]
100
+ s.test_files = ["spec/spec_helper/dummy_chef.rb", "spec/ironfan/cluster_spec.rb", "spec/ironfan/ec2/cloud_provider_spec.rb", "spec/ironfan/ec2/security_group_spec.rb", "spec/spec_helper.rb", "spec/test_config.rb"]
100
101
 
101
102
  if s.respond_to? :specification_version then
102
103
  s.specification_version = 3
@@ -19,6 +19,28 @@ module Gorillib
19
19
  Field.class_eval do
20
20
  field :resolver, Symbol, :default => :read_set_or_underlay_attribute
21
21
  end
22
+
23
+ # Modifies the Gorillib metaprogramming to handle deep recursion on
24
+ # Gorillib::Model collections which would prefer to handle arbitrarily
25
+ # complex resolution requirements via their (custom) receive! method
26
+ module ClassMethods
27
+ def define_collection_receiver(field)
28
+ collection_field_name = field.name; collection_type = field.type
29
+ # @param [Array[Object],Hash[Object]] the collection to merge
30
+ # @return [Gorillib::Collection] the updated collection
31
+ define_meta_module_method("receive_#{collection_field_name}", true) do |coll, &block|
32
+ begin
33
+ existing = read_attribute(collection_field_name)
34
+ if existing and (not collection_type.native?(coll) or existing.respond_to?(:receive!))
35
+ existing.receive!(coll, &block)
36
+ else
37
+ write_attribute(collection_field_name, coll)
38
+ end
39
+ rescue StandardError => err ; err.polish("#{self.class} #{collection_field_name} collection on #{args}'") rescue nil ; raise ; end
40
+ end
41
+ end
42
+ end
43
+
22
44
  end
23
45
 
24
46
  # The attribute :underlay provides an object (preferably another
@@ -50,6 +72,14 @@ module Gorillib
50
72
  result
51
73
  end
52
74
 
75
+ def resolve!
76
+ resolved = resolve
77
+ self.class.fields.each do |field_name, field|
78
+ write_attribute(field_name, resolved.send(field_name.to_sym))
79
+ end
80
+ self
81
+ end
82
+
53
83
  def deep_resolve(field_name)
54
84
  temp = read_set_or_underlay_attribute(field_name)
55
85
  return if temp.nil?
@@ -106,7 +136,7 @@ module Gorillib
106
136
 
107
137
  def read_underlay_attribute(field_name)
108
138
  return if underlay.nil?
109
- underlay.read_resolved_attribute(field_name)
139
+ Gorillib.deep_copy(underlay.read_resolved_attribute(field_name))
110
140
  end
111
141
 
112
142
  def read_set_or_underlay_attribute(field_name)
@@ -13,7 +13,7 @@ module Ironfan
13
13
  # corresponding to
14
14
  def discover!(cluster)
15
15
  # Get fully resolved servers, and build Computers using them
16
- computers = Computers.new(:cluster => cluster.resolve)
16
+ computers = Computers.new(:cluster => cluster)
17
17
  #
18
18
  providers = computers.map{|c| c.providers.values }.flatten.uniq
19
19
  Ironfan.parallel(providers) do |provider|
@@ -7,12 +7,6 @@ module Ironfan
7
7
  def initialize(attrs={},&block)
8
8
  super
9
9
  self.cluster_role Ironfan::Dsl::Role.new(:name => "#{attrs[:name]}_cluster")
10
- self.expand_servers!
11
- end
12
-
13
- def expand_servers!
14
- facets.each {|facet| facet.expand_servers! }
15
- servers
16
10
  end
17
11
 
18
12
  # Utility method to reference all servers from constituent facets
@@ -11,14 +11,11 @@ module Ironfan
11
11
  self.name = attrs[:name] unless attrs[:name].nil?
12
12
  self.facet_role Ironfan::Dsl::Role.new(:name => fullname.sub('-','_'))
13
13
  super
14
+ for i in 0 .. instances-1; server(i); end
14
15
  end
15
16
 
16
17
  def fullname() "#{cluster_name}-#{name}"; end
17
18
 
18
- def expand_servers!
19
- for i in 0..(instances-1) do server(i); end
20
- end
21
-
22
19
  end
23
20
 
24
21
  end
data/lib/ironfan.rb CHANGED
@@ -15,7 +15,7 @@ module Ironfan
15
15
  #
16
16
  # Delegates
17
17
  def self.clusters
18
- Chef::Config[:clusters] ||= Hash.new
18
+ @@clusters
19
19
  end
20
20
 
21
21
  def self.ui=(ui) @ui = ui ; end
@@ -61,10 +61,15 @@ module Ironfan
61
61
  #
62
62
  def self.cluster(name, attrs={}, &block)
63
63
  name = name.to_sym
64
-
65
- cl = ( @@clusters[name] ||= Ironfan::Dsl::Cluster.new({:name => name}) )
66
- cl.receive!(attrs, &block)
67
- cl
64
+ # If this is being called as Ironfan.cluster('foo') with no additional arguments,
65
+ # return the cached cluster object if it exists
66
+ if @@clusters[name] and attrs.empty? and not block_given?
67
+ return @@clusters[name]
68
+ else # Otherwise we're being asked to (re)initialize and cache a cluster definition
69
+ cl = Ironfan::Dsl::Cluster.new(:name => name)
70
+ cl.receive!(attrs, &block)
71
+ @@clusters[name] = cl.resolve
72
+ end
68
73
  end
69
74
 
70
75
  #
@@ -87,9 +92,6 @@ module Ironfan
87
92
  require cluster_file
88
93
  unless @@clusters[cluster] then die("#{cluster_file} was supposed to have the definition for the #{cluster_name} cluster, but didn't") end
89
94
 
90
- # Flesh out the expected servers listed in the facets
91
- @@clusters[cluster].expand_servers!
92
-
93
95
  @@clusters[cluster]
94
96
  end
95
97
 
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ require 'ironfan'
4
+
5
+ describe Ironfan::Dsl::Cluster do
6
+ let (:cluster) do
7
+ Ironfan.cluster "sparky" do
8
+
9
+ cloud(:ec2) do
10
+ security_group(:ssh).authorize_port_range 22..22
11
+ flavor 't1.micro'
12
+ end
13
+
14
+ facet :web do
15
+ instances 3
16
+ end
17
+
18
+ end
19
+ end
20
+
21
+ describe 'web facet server resolution' do
22
+ before { @facet = cluster.facets.values.first }
23
+ subject { @facet }
24
+ its(:name) { should eql "web" }
25
+
26
+ it 'should have the right number of servers' do
27
+ @facet.servers.length.should == 3
28
+ end
29
+
30
+ it 'should have one cloud provider, EC2' do
31
+ @facet.servers[0].clouds.keys.should == [ :ec2 ]
32
+ end
33
+ end
34
+
35
+ end
@@ -5,53 +5,106 @@ require 'ironfan'
5
5
  describe Ironfan::Dsl::Cluster do
6
6
  let (:cluster) do
7
7
  Ironfan.cluster "sparky" do
8
- cloud(:ec2).security_group(:ssh).authorize_port_range 22..22
8
+
9
+ cloud(:ec2) do
10
+ security_group(:ssh).authorize_port_range 22..22
11
+ flavor 't1.micro'
12
+ end
13
+
9
14
  facet :web do
10
15
  cloud(:ec2).security_group("sparky-web").authorize_port_range(80)
16
+ cloud(:ec2).flavor 'm1.small'
11
17
  end
18
+
19
+ facet :mysql do
20
+ # My what a permissive database you have.
21
+ cloud(:ec2).security_group("sparky-mysql").authorize_port_range(3306)
22
+ cloud(:ec2).flavor 'm1.xlarge'
23
+ end
24
+
12
25
  end
13
26
  end
14
-
27
+
15
28
  describe 'cluster definition' do
16
29
  subject { cluster }
17
-
30
+
18
31
  its(:name) { should eql "sparky" }
19
32
  its(:environment) { should eql :_default }
20
33
  its(:run_list) { should eql [] }
21
-
34
+
22
35
  describe 'facets' do
23
36
  before { @facets = cluster.facets }
24
37
  subject { @facets.values }
25
- its(:length) { should eql 1 }
26
-
38
+ its(:length) { should eql 2 }
39
+
27
40
  describe 'web facet' do
28
41
  before { @facet = @facets.values.first }
29
42
  subject { @facet }
30
43
  its(:name) { should eql "web" }
31
-
44
+
45
+ it 'should have the correct flavor' do
46
+ @facet.cloud(:ec2).flavor.should == 'm1.small'
47
+ end
48
+
49
+ it 'should have the right number of servers' do
50
+ @facet.servers.length.should == 1
51
+ end
52
+
32
53
  describe 'security groups' do
33
54
  before { @groups = @facet.clouds.values.first.security_groups.values }
34
55
  subject { @groups }
35
-
56
+
36
57
  its(:length) { should eql 2 }
37
-
58
+
38
59
  it 'authorizes ssh on port 22 from anywhere' do
39
- ssh_auth = @groups.first
40
- ssh_auth.range_authorizations.first.should eql [22..22, "0.0.0.0/0", "tcp"]
60
+ ssh_auth = @groups.detect { |g| g.name == 'ssh' }
61
+ ssh_auth.should_not be_nil
62
+ ssh_auth.range_authorizations.select { |g| g.eql? [22..22, "0.0.0.0/0", "tcp"] }.should_not be_empty
41
63
  end
42
-
64
+
43
65
  it 'authorizes HTTP on port 80 from anywhere' do
44
- http_auth = @groups.last
45
- http_auth.range_authorizations.first.should eql [80..80, "0.0.0.0/0", "tcp"]
66
+ http_auth = @groups.detect { |g| g.name == 'sparky-web' }
67
+ http_auth.should_not be_nil
68
+ http_auth.range_authorizations.select { |g| g.eql? [80..80, "0.0.0.0/0", "tcp"] }.should_not be_empty
69
+ end
70
+
71
+ end
72
+ end
73
+
74
+ describe 'mysql facet' do
75
+ before { @facet = @facets.values.last }
76
+ subject { @facet }
77
+ its(:name) { should eql "mysql" }
78
+
79
+ it 'should have the correct flavor' do
80
+ @facet.cloud(:ec2).flavor.should == 'm1.xlarge'
81
+ end
82
+
83
+ describe 'security groups' do
84
+ before { @groups = @facet.clouds.values.first.security_groups.values }
85
+ subject { @groups }
86
+
87
+ its(:length) { should eql 2 }
88
+
89
+ it 'authorizes ssh on port 22 from anywhere' do
90
+ ssh_auth = @groups.detect { |g| g.name == 'ssh' }
91
+ ssh_auth.should_not be_nil
46
92
  end
93
+
94
+ it 'authorizes MySQL on port 3306 from anywhere' do
95
+ mysql_auth = @groups.detect { |g| g.name == 'sparky-mysql' }
96
+ mysql_auth.should_not be_nil
97
+ mysql_auth.range_authorizations.select { |g| g.eql? [3306..3306, "0.0.0.0/0", "tcp"] }.should_not be_empty
98
+ end
99
+
47
100
  end
48
101
  end
49
-
102
+
103
+
50
104
  end
51
-
105
+
52
106
  describe 'clouds' do
53
-
107
+
54
108
  end
55
109
  end
56
110
  end
57
-
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ironfan
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 4.2.0
5
+ version: 4.2.1
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-09-29 00:00:00 Z
13
+ date: 2012-10-01 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: chef
@@ -211,6 +211,7 @@ files:
211
211
  - lib/ironfan/provider/virtualbox/machine.rb
212
212
  - lib/ironfan/requirements.rb
213
213
  - spec/ironfan/cluster_spec.rb
214
+ - spec/ironfan/ec2/cloud_provider_spec.rb
214
215
  - spec/ironfan/ec2/security_group_spec.rb
215
216
  - spec/spec_helper.rb
216
217
  - spec/spec_helper/dummy_chef.rb
@@ -229,7 +230,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
229
230
  requirements:
230
231
  - - ">="
231
232
  - !ruby/object:Gem::Version
232
- hash: 2633727153528237962
233
+ hash: -2791351356463943124
233
234
  segments:
234
235
  - 0
235
236
  version: "0"
@@ -249,6 +250,7 @@ summary: Ironfan allows you to orchestrate not just systems but clusters of mach
249
250
  test_files:
250
251
  - spec/spec_helper/dummy_chef.rb
251
252
  - spec/ironfan/cluster_spec.rb
253
+ - spec/ironfan/ec2/cloud_provider_spec.rb
252
254
  - spec/ironfan/ec2/security_group_spec.rb
253
255
  - spec/spec_helper.rb
254
256
  - spec/test_config.rb