ironfan 4.2.0 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
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