souffle 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/Gemfile +9 -3
  2. data/README.md +6 -0
  3. data/bin/{souffle-server → souffle} +0 -0
  4. data/lib/souffle.rb +8 -8
  5. data/lib/souffle/application.rb +15 -10
  6. data/lib/souffle/application/souffle-server.rb +90 -5
  7. data/lib/souffle/config.rb +88 -59
  8. data/lib/souffle/daemon.rb +156 -0
  9. data/lib/souffle/exceptions.rb +29 -17
  10. data/lib/souffle/http.rb +43 -0
  11. data/lib/souffle/log.rb +11 -14
  12. data/lib/souffle/node.rb +91 -53
  13. data/lib/souffle/node/runlist.rb +16 -18
  14. data/lib/souffle/node/runlist_item.rb +43 -36
  15. data/lib/souffle/node/runlist_parser.rb +60 -62
  16. data/lib/souffle/polling_event.rb +110 -0
  17. data/lib/souffle/provider.rb +231 -23
  18. data/lib/souffle/provider/aws.rb +654 -7
  19. data/lib/souffle/provider/vagrant.rb +42 -5
  20. data/lib/souffle/provisioner.rb +55 -0
  21. data/lib/souffle/provisioner/node.rb +157 -0
  22. data/lib/souffle/provisioner/system.rb +195 -0
  23. data/lib/souffle/redis_client.rb +8 -0
  24. data/lib/souffle/redis_mixin.rb +40 -0
  25. data/lib/souffle/server.rb +42 -8
  26. data/lib/souffle/ssh_monkey.rb +8 -0
  27. data/lib/souffle/state.rb +16 -0
  28. data/lib/souffle/system.rb +139 -37
  29. data/lib/souffle/template.rb +30 -0
  30. data/lib/souffle/templates/Vagrantfile.erb +41 -0
  31. data/lib/souffle/version.rb +6 -0
  32. data/spec/config_spec.rb +20 -0
  33. data/spec/log_spec.rb +24 -0
  34. data/spec/{runlist_parser_spec.rb → node/runlist_parser_spec.rb} +1 -1
  35. data/spec/{runlist_spec.rb → node/runlist_spec.rb} +1 -1
  36. data/spec/node_spec.rb +43 -8
  37. data/spec/provider_spec.rb +56 -0
  38. data/spec/providers/aws_provider_spec.rb +114 -0
  39. data/spec/providers/vagrant_provider_spec.rb +22 -0
  40. data/spec/provisioner_spec.rb +47 -0
  41. data/spec/spec_helper.rb +8 -0
  42. data/spec/system_spec.rb +242 -13
  43. data/spec/template_spec.rb +20 -0
  44. data/spec/templates/example_template.erb +1 -0
  45. metadata +125 -30
  46. data/bin/souffle-worker +0 -7
  47. data/lib/souffle/application/souffle-worker.rb +0 -46
  48. data/lib/souffle/providers.rb +0 -2
  49. data/lib/souffle/worker.rb +0 -14
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
3
  describe "Souffle::Node::RunListParser" do
4
4
  it "should be able to check whether a hash name is a valid word" do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
3
  describe "Souffle::Node::RunList" do
4
4
  it "should be able to add a runlist item onto the runlist" do
data/spec/node_spec.rb CHANGED
@@ -32,21 +32,28 @@ describe "Souffle::Node" do
32
32
  end
33
33
 
34
34
  it "should be able to describe a single node" do
35
- @node.run_list << "recipe[chef_server::rubygems_install]"
36
- @node.run_list << "role[dns_server]"
35
+ rlist = [
36
+ "recipe[chef_server::rubygems_install]",
37
+ "role[dns_server]" ]
38
+ rlist.each { |rl| @node.run_list << rl }
39
+ @node.run_list.each do |rl_item|
40
+ rlist.include?(rl_item.to_s).should eql(true)
41
+ end
37
42
  end
38
43
 
39
44
  it "should be able to test whether or not a node depends on another" do
40
45
  @node.run_list << "role[dns_server]"
41
46
  node2 = Souffle::Node.new
42
47
  node2.dependencies << "role[dns_server]"
43
- node2.depends_on?(@node).should eql(true)
48
+ node2.depends_on?(@node).should eql(
49
+ [ true, [Souffle::Node::RunListItem.new("role[dns_server]")] ]
50
+ )
44
51
  end
45
52
 
46
53
  it "should not depend on another node when there are no dependencies" do
47
54
  @node.run_list << "role[dns_server]"
48
55
  node2 = Souffle::Node.new
49
- node2.depends_on?(@node).should eql(false)
56
+ node2.depends_on?(@node).should eql([ false, [] ])
50
57
  end
51
58
 
52
59
  it "should be able to add child nodes" do
@@ -55,9 +62,15 @@ describe "Souffle::Node" do
55
62
  @node.children.should eql([child])
56
63
  end
57
64
 
65
+ it "should not duplicate a child node that's added" do
66
+ child = Souffle::Node.new
67
+ @node.add_child(child)
68
+ @node.add_child(child)
69
+ @node.children.should eql([child])
70
+ end
71
+
58
72
  it "should raise and error on adding an invalid child" do
59
- child = []
60
- lambda { node.add_child(child) }.should raise_error
73
+ lambda { node.add_child([]) }.should raise_error
61
74
  end
62
75
 
63
76
  it "should be able to iterate across children" do
@@ -81,7 +94,29 @@ describe "Souffle::Node" do
81
94
  @node.should eql(node2)
82
95
  end
83
96
 
84
- it "should have an initial state of `:uninitialized`" do
85
- @node.state_name.should eql(:uninitialized)
97
+ it "should have a depency weight of 1 with no parents" do
98
+ @node.weight.should eql(1)
99
+ end
100
+
101
+ it "should have a dependency weight of at least 2 with a parent" do
102
+ parent = Souffle::Node.new
103
+ parent.add_child(@node)
104
+ (@node.weight >= 2).should eql(true)
105
+ end
106
+
107
+ it "should have a name and be able to set it" do
108
+ @node.name = "AwesomeName"
109
+ @node.name.should eql("AwesomeName")
110
+ end
111
+
112
+ it "should be able to get node options with try_opt" do
113
+ @node.options[:example_opt] = "sporkmejohhny"
114
+ @node.try_opt(:example_opt).should eql("sporkmejohhny")
115
+ end
116
+
117
+ it "should pass-thru to config options when they do not exist" do
118
+ Souffle::Config[:example_passthru] = "blehk"
119
+ @node.try_opt(:example_passthru).should eql("blehk")
120
+ Souffle::Config.configuration.delete(:example_passthru)
86
121
  end
87
122
  end
@@ -0,0 +1,56 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Souffle::Provider::Base" do
4
+ before(:each) do
5
+ @provider = Souffle::Provider::Base.new
6
+ end
7
+
8
+ after(:each) do
9
+ @provider = nil
10
+ end
11
+
12
+ it "should have Base as a default name" do
13
+ @provider.name.should eql("Base")
14
+ end
15
+
16
+ it "should raise errors on non-overridden create_system" do
17
+ n = Souffle::Node.new
18
+ lambda { @provider.create_system(n) }.should raise_error
19
+ end
20
+
21
+ it "should raise errors on non-overridden create_node" do
22
+ n = Souffle::Node.new
23
+ lambda { @provider.create_node(n) }.should raise_error
24
+ end
25
+
26
+ it "should raise errors on non-overridden create_raid" do
27
+ lambda { @provider.create_raid }.should raise_error
28
+ end
29
+
30
+ it "should have an ssh_key_path that matches the provider name" do
31
+ @provider.send(:ssh_key_path).should eql(
32
+ "/etc/souffle/ssh/#{@provider.name.downcase}")
33
+ end
34
+
35
+ it "should have a relative ssh key helpers" do
36
+ base_path = "/etc/souffle/ssh/base"
37
+ @provider.send(:ssh_key, "mykey").should eql("#{base_path}/mykey")
38
+ end
39
+
40
+ it "should be able to generate chef-solo json for a node." do
41
+ node = Souffle::Node.new
42
+ node.name = "TheBestOne"
43
+ rlist = [ "recipe[chef_server::rubygems_install]", "role[dns_server]" ]
44
+ rlist.each { |rl| node.run_list << rl }
45
+
46
+ runlist = {
47
+ "domain" => "souffle",
48
+ "run_list" => [
49
+ "recipe[chef_server::rubygems_install]",
50
+ "role[dns_server]"
51
+ ]
52
+ }
53
+
54
+ JSON.parse(@provider.generate_chef_json(node)).should eql(runlist)
55
+ end
56
+ end
@@ -0,0 +1,114 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Souffle::Provider::AWS" do
4
+ include Helpers
5
+
6
+ before(:each) do
7
+ get_config
8
+ @provider = Souffle::Provider::AWS.new
9
+ end
10
+
11
+ after(:each) do
12
+ @provider = nil
13
+ end
14
+
15
+ # Note:
16
+ # All of the AWS routines will only run if you are provided a
17
+ # valid aws_access_key and aws_access_secret.
18
+
19
+ it "should be able to see whether the configuration has vpc setup" do
20
+ aws_vpc_id = "vpc-124ae13"
21
+ aws_subnet_id = "subnet-24f6a87f"
22
+ node = Souffle::Node.new
23
+
24
+ Souffle::Config[:aws_vpc_id] = aws_vpc_id
25
+ Souffle::Config[:aws_subnet_id] = aws_subnet_id
26
+
27
+ @provider.using_vpc?(node).should eql(true)
28
+ end
29
+
30
+ it "should not use vpc when the keys are missing" do
31
+ aws_vpc_id = "vpc-124ae13"
32
+ aws_subnet_id = "subnet-24f6a87f"
33
+ node = Souffle::Node.new
34
+
35
+ Souffle::Config[:aws_vpc_id] = aws_vpc_id
36
+ Souffle::Config[:aws_subnet_id] = nil
37
+ @provider.using_vpc?(node).should eql(false)
38
+
39
+ Souffle::Config[:aws_vpc_id] = nil
40
+ Souffle::Config[:aws_subnet_id] = aws_subnet_id
41
+ @provider.using_vpc?(node).should eql(false)
42
+
43
+ Souffle::Config[:aws_vpc_id] = nil
44
+ Souffle::Config[:aws_subnet_id] = nil
45
+ @provider.using_vpc?(node).should eql(false)
46
+ end
47
+
48
+ it "should be able to generate a unique tag" do
49
+ tag1 = @provider.generate_tag
50
+ tag2 = @provider.generate_tag
51
+ tag1.should_not eql(tag2)
52
+ end
53
+
54
+ it "should be able to generate a unique tag with a prefix" do
55
+ @provider.generate_tag("example").include?("example").should eql(true)
56
+ end
57
+
58
+ it "should return a list of instance ids for a list of nodes" do
59
+ node1 = Souffle::Node.new
60
+ node2 = Souffle::Node.new
61
+ node3 = Souffle::Node.new
62
+
63
+ node1.options[:aws_instance_id] = "1a"
64
+ node2.options[:aws_instance_id] = "2b"
65
+ node3.options[:aws_instance_id] = "3c"
66
+
67
+ nodelist = [node1, node2, node3]
68
+ @provider.instance_id_list(nodelist).should eql(["1a", "2b", "3c"])
69
+ end
70
+ end
71
+
72
+ describe "Souffle::Provider::AWS (live)", :live => true do
73
+ include Helpers
74
+
75
+ before(:each) do
76
+ get_config
77
+ @provider = Souffle::Provider::AWS.new
78
+ end
79
+
80
+ after(:each) do
81
+ @provider = nil
82
+ end
83
+
84
+ it "should be able to launch and provision an entire system" do
85
+ EM.run do
86
+ system = Souffle::System.new
87
+
88
+ masternode = Souffle::Node.new
89
+ masternode.name = "MasterNode"
90
+ masternode.run_list << "recipe[git]"
91
+ masternode.options[:aws_ebs_size] = 1
92
+ masternode.options[:volume_count] = 2
93
+
94
+ child_node1 = Souffle::Node.new
95
+ child_node1.name = "child node 1"
96
+ child_node1.options[:aws_ebs_size] = 2
97
+ child_node1.options[:volume_count] = 2
98
+
99
+ child_node2 = Souffle::Node.new
100
+ child_node2.name = "child node 2"
101
+ child_node2.options[:aws_ebs_size] = 3
102
+ child_node2.options[:volume_count] = 2
103
+
104
+ system.add(masternode)
105
+ system.add(child_node1)
106
+ system.add(child_node2)
107
+ @provider.create_system(system)
108
+
109
+ EM::Timer.new(300) do
110
+ EM.stop
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Souffle::Provider::Vagrant" do
4
+ include Helpers
5
+
6
+ before(:each) do
7
+ get_config
8
+ @provider = Souffle::Provider::Vagrant.new
9
+ end
10
+
11
+ after(:each) do
12
+ @provider = nil
13
+ Souffle::Config[:vagrant_dir] = "/#{ENV['HOME']}/vagrant/vms"
14
+ end
15
+
16
+ it "should have setup initialize the access key and secret" do
17
+ example_vagrant_dir = "/path/to/vagrant/vms"
18
+ Souffle::Config[:vagrant_dir] = "/path/to/vagrant/vms"
19
+ @provider = Souffle::Provider::Vagrant.new
20
+ @provider.vagrant_dir.should eql(example_vagrant_dir)
21
+ end
22
+ end
@@ -0,0 +1,47 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Souffle::Provisioner" do
4
+ include Helpers
5
+
6
+ before(:each) do
7
+ get_config
8
+ Souffle::Config[:provider] = "Vagrant"
9
+ @provisioner = Souffle::Provisioner.new
10
+ end
11
+
12
+ after(:each) do
13
+ @provisioner = nil
14
+ end
15
+
16
+ it "should be able to initialize a Vagrant provider" do
17
+ @provisioner.provider.name.should eql("Vagrant")
18
+ end
19
+
20
+ it "should be raise an error on an invalid provider" do
21
+ Souffle::Config[:provider] = "CompletelyInvalidProvider"
22
+ d = lambda { Souffle::Provisioner.new }
23
+ d.should raise_error
24
+ end
25
+
26
+ it "should be able to initialize an AWS provider" do
27
+ Souffle::Config[:provider] = "AWS"
28
+ @provisioner = Souffle::Provisioner.new
29
+ @provisioner.provider.name.should eql("AWS")
30
+ end
31
+
32
+ it "should be able to setup an Vagrant provider" do
33
+ Souffle::Config[:provider] = "Vagrant"
34
+ @provisioner = Souffle::Provisioner.new
35
+ end
36
+
37
+ it "should be able to setup an AWS provider" do
38
+ Souffle::Config[:provider] = "AWS"
39
+ @provisioner = Souffle::Provisioner.new
40
+ end
41
+
42
+ it "raises an InvalidProvider error when the provider doesn't exist" do
43
+ Souffle::Config[:provider] = "UnholyProviderOfBadness"
44
+ d = lambda { Souffle::Provisioner.new }
45
+ d.should raise_error
46
+ end
47
+ end
data/spec/spec_helper.rb CHANGED
@@ -28,5 +28,13 @@ require 'souffle'
28
28
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
29
29
 
30
30
  RSpec.configure do |config|
31
+ if ENV['AWS_LIVE'].to_s != "true"
32
+ config.filter_run_excluding :live => true
33
+ end
34
+ end
31
35
 
36
+ module Helpers
37
+ def get_config
38
+ Souffle::Config.from_file("/etc/souffle/souffle.rb")
39
+ end
32
40
  end
data/spec/system_spec.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'set'
2
3
 
3
4
  describe "Souffle::System" do
4
5
  before(:each) do
@@ -9,27 +10,255 @@ describe "Souffle::System" do
9
10
  @system = nil
10
11
  end
11
12
 
12
- it "should be able to setup a Vagrant provider" do
13
- @system.provider.name.should eql("Vagrant")
13
+ it "should be able to find all of the nodes with no parents" do
14
+ node1 = Souffle::Node.new
15
+ node2 = Souffle::Node.new
16
+ node3 = Souffle::Node.new
17
+ node4 = Souffle::Node.new
18
+
19
+ node1.dependencies << "role[awesomeone]"
20
+ node2.dependencies << "recipe[bleh]"
21
+
22
+ @system.add(node1)
23
+ @system.add(node2)
24
+ @system.add(node3)
25
+ @system.add(node4)
26
+
27
+ @system.roots.to_set.should eql(Set.new([node3, node4]))
14
28
  end
15
29
 
16
- it "should be able to setup an AWS provider" do
17
- @system = Souffle::System.new("AWS")
18
- @system.provider.name.should eql("AWS")
30
+ it "should be able to add a root node" do
31
+ node = Souffle::Node.new
32
+ @system.add(node)
33
+ @system.roots.should eql([node])
19
34
  end
20
35
 
21
- it "should raise an InvalidProvider error when the provider doesn't exist" do
22
- d = lambda { @system = Souffle::System.new("UnholyProviderOfBadness") }
23
- d.should raise_error
36
+ it "should be able to determine dependant nodes" do
37
+ node1 = Souffle::Node.new
38
+ node2 = Souffle::Node.new
39
+
40
+ node1.run_list << "role[some_silly_role]"
41
+ node2.dependencies << "role[some_silly_role]"
42
+
43
+ @system.add(node1)
44
+ @system.add(node2)
45
+
46
+ @system.rebalance_nodes
47
+ @system.dependent_nodes.should eql([node2])
24
48
  end
25
49
 
26
- it "should be able to add a root node" do
50
+ it "should be able to clear all nodes parent and child heirarchy" do
51
+ node1 = Souffle::Node.new
52
+ node2 = Souffle::Node.new
53
+
54
+ node1.run_list << "role[some_silly_role]"
55
+ node2.dependencies << "role[some_silly_role]"
56
+
57
+ @system.add(node1)
58
+ @system.add(node2)
59
+ @system.rebalance_nodes
60
+
61
+ node1.children.include?(node2).should eql(true)
62
+ node2.parents.include?(node1).should eql(true)
63
+
64
+ @system.clear_node_heirarchy
65
+ node1.children.should eql([])
66
+ node2.parents.should eql([])
67
+ end
68
+
69
+ it "should be able to get the node dependencies on a system" do
70
+ node1 = Souffle::Node.new
71
+ node2 = Souffle::Node.new
72
+ node3 = Souffle::Node.new
73
+
74
+ node1.dependencies << "role[example_role]"
75
+ node1.dependencies << "recipe[the_best_one]"
76
+
77
+ node2.run_list << "role[example_role]"
78
+ node3.run_list << "recipe[the_best_one]"
79
+
80
+ @system.add(node1)
81
+ @system.add(node2)
82
+ @system.add(node3)
83
+
84
+ @system.dependencies_on_system(node1).should eql(
85
+ [ [node2, [Souffle::Node::RunListItem.new("role[example_role]")] ],
86
+ [node3, [Souffle::Node::RunListItem.new("recipe[the_best_one]")] ]
87
+ ] )
88
+ end
89
+
90
+ it "should be able to optimize a rebalanced system of nodes" do
91
+ target = Souffle::Node.new
92
+ heavy1 = Souffle::Node.new
93
+ heavy2 = Souffle::Node.new
94
+ root_node = Souffle::Node.new
95
+ light_node = Souffle::Node.new
96
+
97
+ target.dependencies << "role[example_role]"
98
+ target.dependencies << "recipe[the_best_one]"
99
+
100
+ heavy1.run_list << "role[example_role]"
101
+ heavy2.run_list << "recipe[the_best_one]"
102
+ heavy1.dependencies << "recipe[heavy]"
103
+ heavy2.dependencies << "recipe[heavy]"
104
+
105
+ root_node.run_list << "recipe[heavy]"
106
+
107
+ light_node.run_list << "role[example_role]"
108
+ light_node.run_list << "recipe[the_best_one]"
109
+
110
+ @system.add(target)
111
+ @system.add(heavy1)
112
+ @system.add(heavy2)
113
+ @system.add(root_node)
114
+ @system.add(light_node)
115
+
116
+ @system.rebalance_nodes
117
+ @system.optimized_node_dependencies(target).should eql([light_node])
118
+ end
119
+
120
+ it "should have children nodes that can identify the system" do
121
+ target = Souffle::Node.new
122
+ heavy1 = Souffle::Node.new
123
+ heavy2 = Souffle::Node.new
124
+ root_node = Souffle::Node.new
125
+ light_node = Souffle::Node.new
126
+
127
+ target.dependencies << "role[example_role]"
128
+ target.dependencies << "recipe[the_best_one]"
129
+
130
+ heavy1.run_list << "role[example_role]"
131
+ heavy2.run_list << "recipe[the_best_one]"
132
+ heavy1.dependencies << "recipe[heavy]"
133
+ heavy2.dependencies << "recipe[heavy]"
134
+
135
+ root_node.run_list << "recipe[heavy]"
136
+
137
+ light_node.run_list << "role[example_role]"
138
+ light_node.run_list << "recipe[the_best_one]"
139
+
140
+ @system.add(target)
141
+ @system.add(heavy1)
142
+ @system.add(heavy2)
143
+ @system.add(root_node)
144
+ @system.add(light_node)
145
+
146
+ @system.rebalance_nodes
147
+ @system.nodes.each { |n| n.system.should eql(@system) }
148
+ end
149
+
150
+ it "should raise an exception on an incorrect system hash" do
151
+ sys = {}
152
+ lambda { Souffle::System.from_hash(sys) }.should raise_error
153
+ end
154
+
155
+ it "should be able to get system options with try_opt" do
156
+ @system.options[:example_opt] = "sporkmejohhny"
157
+ @system.try_opt(:example_opt).should eql("sporkmejohhny")
158
+ end
159
+
160
+ it "should pass-thru to config options when they do not exist" do
161
+ Souffle::Config[:example_passthru] = "blehk"
162
+ @system.try_opt(:example_passthru).should eql("blehk")
163
+ Souffle::Config.configuration.delete(:example_passthru)
164
+ end
165
+
166
+ it "should let child nodes get system opts with pass-thru" do
27
167
  node = Souffle::Node.new
28
- @system.root = node
29
- @system.root.should eql(node)
168
+ @system.add(node)
169
+ @system.options[:example_opt] = "sporkmejohhny"
170
+ @system.nodes.first.try_opt(:example_opt).should eql("sporkmejohhny")
171
+ end
172
+
173
+ it "should pass-thru to config options when they do not exist" do
174
+ Souffle::Config[:example_passthru] = "blehk"
175
+ @system.try_opt(:example_passthru).should eql("blehk")
176
+ Souffle::Config.configuration.delete(:example_passthru)
177
+ end
178
+
179
+ it "should be able to generate a system from a hash" do
180
+ sys = {
181
+ :nodes => [
182
+ { :name => "parent_node",
183
+ :run_list => ["role[somerole]"],
184
+ :dependencies => [] },
185
+ { :name => "lone_node",
186
+ :run_list => ["role[bestone]"],
187
+ :dependencies => [] },
188
+ { :name => "child_node",
189
+ :run_list => ["recipe[base]"],
190
+ :dependencies => ["role[somerole]"] }
191
+ ]
192
+ }
193
+
194
+ new_sys = Souffle::System.from_hash(sys)
195
+ new_sys.rebalance_nodes
196
+
197
+ parent = new_sys.nodes.select { |n| n.name == "parent_node" }.first
198
+ parent.children.first.name.should eql("child_node")
199
+ new_sys.roots.size.should eql(2)
200
+ new_sys.dependent_nodes.size.should eql(1)
30
201
  end
31
202
 
32
- it "should have an initial state of `:uninitialized`" do
33
- @system.state_name.should eql(:uninitialized)
203
+ it "should be able to generate system options and merge from a hash" do
204
+ sys = {
205
+ :options => { :type => "chef" },
206
+ :nodes => [
207
+ { :name => "parent_node",
208
+ :options => { :type => "chef-solo" },
209
+ :run_list => ["role[somerole]"],
210
+ :dependencies => [] },
211
+ { :name => "lone_node",
212
+ :run_list => ["role[bestone]"],
213
+ :dependencies => [] },
214
+ { :name => "child_node",
215
+ :run_list => ["recipe[base]"],
216
+ :dependencies => ["role[somerole]"] }
217
+ ]
218
+ }
219
+
220
+ new_sys = Souffle::System.from_hash(sys)
221
+ new_sys.rebalance_nodes
222
+
223
+ parent = new_sys.nodes.select { |n| n.name == "parent_node" }.first
224
+ parent.children.first.name.should eql("child_node")
225
+ parent.options.should eql({ :attributes => {}, :type => "chef-solo" })
226
+ parent.children.first.options.should eql({
227
+ :attributes => {}, :type => "chef" })
228
+
229
+ new_sys.roots.size.should eql(2)
230
+ new_sys.dependent_nodes.size.should eql(1)
231
+ end
232
+
233
+ it "should have the same system in a hash format as it does in dsl" do
234
+ sys = {
235
+ :nodes => [
236
+ { :name => "MasterNode",
237
+ :run_list => [ "recipe[gem]",
238
+ "recipe[git]" ],
239
+ :options => {
240
+ :gem => { :source => "http://gem.test.com" },
241
+ :aws_ebs_size => 10,
242
+ :volume_count => 2
243
+ }
244
+ }
245
+ ]
246
+ }
247
+
248
+ sys2 = Souffle::System.new
249
+ masternode = Souffle::Node.new
250
+ masternode.name = "MasterNode"
251
+ masternode.run_list << "recipe[gem]"
252
+ masternode.run_list << "recipe[git]"
253
+ masternode.options[:gem] = { :source => "http://gem.test.com" }
254
+ masternode.options[:aws_ebs_size] = 10
255
+ masternode.options[:volume_count] = 2
256
+ sys2.add(masternode)
257
+
258
+ new_sys = Souffle::System.from_hash(sys)
259
+
260
+ parent = new_sys.nodes.select { |n| n.name == "MasterNode" }.first
261
+ parent.run_list.should eql(masternode.run_list)
262
+ parent.options.should eql(masternode.options)
34
263
  end
35
264
  end