souffle 0.0.1 → 0.0.2

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.
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