souffle 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,19 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ### v0.0.4
3
4
 
4
- ### v0.0.1
5
+ * Added chef-client support
6
+ * Added warning for cli one-off runs
7
+ * Added provider plugins support
8
+ * Added provider helper methods
9
+ * Updated documentation
10
+ * System timeout set to 10 minutes
11
+ * Updated handler for node provisioning
12
+ * Updated handler for system provisioning
13
+ * Node provisioning updates are now evented
14
+ * Updated eventmachine to 1.0.0
15
+ * Fixed timing issue with mdadm install
5
16
 
6
- * Application framework laid out
7
- * Initial node state machine
8
- * Initial system state machine
9
- * Added AWS provider
10
- * Initial command line interface
11
- * Added daemonization
12
- * Added singleton configuration
13
- * Initial runlist parser
14
- * Initial dependency traversal
15
- * System rebalancing (pre-provisioning)
16
- * Added REST API
17
+ ### v0.0.3
18
+
19
+ * Multiple documentation updates
20
+ * AWS provider
21
+ * Tags now use `hex(4)` instead of `hex(6)`
22
+ * Deprecated default tag prefix
23
+ * Added chef roles support to providers
24
+ * Fixed /version url link
25
+ * Added `tag`, `domain`, and `fqdn` node helpers
26
+ * Bugfix for repo_path
27
+ * Hostname is now set at provisioning
17
28
 
18
29
  ### v0.0.2
19
30
 
@@ -29,14 +40,16 @@
29
40
  * Optimized AWS polling mechanism
30
41
  * Optimized AWS creation ordering
31
42
 
32
- ### v0.0.3
43
+ ### v0.0.1
33
44
 
34
- * Multiple documentation updates
35
- * AWS provider
36
- * Tags now use `hex(4)` instead of `hex(6)`
37
- * Deprecated default tag prefix
38
- * Added chef roles support to providers
39
- * Fixed /version url link
40
- * Added `tag`, `domain`, and `fqdn` node helpers
41
- * Bugfix for repo_path
42
- * Hostname is now set at provisioning
45
+ * Application framework laid out
46
+ * Initial node state machine
47
+ * Initial system state machine
48
+ * Added AWS provider
49
+ * Initial command line interface
50
+ * Added daemonization
51
+ * Added singleton configuration
52
+ * Initial runlist parser
53
+ * Initial dependency traversal
54
+ * System rebalancing (pre-provisioning)
55
+ * Added REST API
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source "http://rubygems.org"
4
4
  # gem "activesupport", ">= 2.3.5"
5
5
 
6
6
  gem "yajl-ruby", "~> 1.1.0"
7
- gem "eventmachine", "~> 0.12.10"
7
+ gem "eventmachine", "~> 1.0.0"
8
8
  gem "amqp", "~> 0.9.7"
9
9
  gem "state_machine", "~> 1.1.2"
10
10
  gem "em-ssh", "~> 0.4.0"
data/README.md CHANGED
@@ -48,9 +48,9 @@ As an example system we'll generate two nodes that both are provisioned with `so
48
48
 
49
49
  ```json
50
50
  {
51
- "provider": "aws",
52
51
  "user": "josh",
53
52
  "options": {
53
+ "provider": "aws",
54
54
  "domain": "mydomain.com",
55
55
  "type": "solo",
56
56
  "aws_ebs_size": 10,
@@ -30,4 +30,7 @@ class Souffle::Exceptions
30
30
 
31
31
  # The AWS Keys are invalid.
32
32
  class InvalidAwsKeys < RuntimeError; end
33
+
34
+ # Plugin does not exist.
35
+ class PluginDoesNotExist < RuntimeError; end
33
36
  end
data/lib/souffle/http.rb CHANGED
@@ -35,9 +35,8 @@ class Souffle::Http < Sinatra::Base
35
35
  Souffle::Log.debug msg
36
36
  Souffle::Log.debug data.to_s
37
37
 
38
- provider = Souffle::Provider::AWS.new
39
-
40
38
  system = Souffle::System.from_hash(data)
39
+ provider = Souffle::Provider.plugin(system.try_opt(:provider)).new
41
40
  system_tag = provider.create_system(system)
42
41
 
43
42
  begin
data/lib/souffle/node.rb CHANGED
@@ -99,15 +99,22 @@ class Souffle::Node
99
99
  nil
100
100
  end
101
101
 
102
+ # Returns the current system provider.
103
+ #
104
+ # @return [ Souffle::Provider::Base ] The current system provider.
105
+ def provider
106
+ system.provider
107
+ end
108
+
102
109
  # The logging prefix for the given node.
103
- #
110
+ #
104
111
  # @return [ String ] The logging prefix for the given node.
105
112
  def log_prefix
106
113
  "[#{tag}: #{name}]"
107
114
  end
108
115
 
109
116
  # The tag for the given node.
110
- #
117
+ #
111
118
  # @return [ String ] The tag for the given node.
112
119
  def tag
113
120
  try_opt(:tag)
@@ -3,12 +3,33 @@ require 'tmpdir'
3
3
 
4
4
  # A metal provider module (Describes AWS, Softlayer, etc).
5
5
  module Souffle::Provider
6
+ class << self
7
+ # Returns the list of available provider plugins.
8
+ #
9
+ # @return [ Array ] The list of available provider plugins.
10
+ def plugins
11
+ constants.map { |k| k.to_s.downcase }
12
+ end
13
+
14
+ # Returns the plugin with the given name.
15
+ #
16
+ # @param [ String ] name The name of the plugin to select.
17
+ #
18
+ # @return [ Souffle::Provider::Base ] The plugin with the given name.
19
+ def plugin(name)
20
+ plug = constants.select { |k| k.to_s.downcase == name.downcase }.first
21
+ Souffle::Provider.const_get(plug)
22
+ rescue Souffle::Exceptions::PluginDoesNotExist => e
23
+ Souffle::Log.error "#{e.message}:\n#{e.backtrace.join("\n")}"
24
+ end
25
+ end
26
+
6
27
  # The souffle cloud provider class.
7
28
  class Base
8
29
  attr_accessor :system
9
30
 
10
31
  # Initialize a new provider for a given system.
11
- #
32
+ #
12
33
  # @param [ Souffle::System ] system The system to provision.
13
34
  def initialize(system=Souffle::System.new)
14
35
  @system ||= system
@@ -16,7 +37,7 @@ module Souffle::Provider
16
37
  end
17
38
 
18
39
  # The name of the given provider.
19
- #
40
+ #
20
41
  # @return [ String ] The name of the given provider.
21
42
  def name
22
43
  self.class.name.split('::').last
@@ -30,7 +51,7 @@ module Souffle::Provider
30
51
  #
31
52
  # @raise [Souffle::Exceptions::Provider] This definition must be
32
53
  # overrridden.
33
- #
54
+ #
34
55
  # @param [ Souffle::System ] system The system to instantiate.
35
56
  # @param [ String ] tag The tag to use for the system.
36
57
  def create_system(system, tag=nil)
@@ -39,7 +60,7 @@ module Souffle::Provider
39
60
  end
40
61
 
41
62
  # Takes a node definition and begins the provisioning process.
42
- #
63
+ #
43
64
  # @param [ Souffle::Node ] node The node to instantiate.
44
65
  # @param [ String ] tag The tag to use for the node.
45
66
  def create_node(node, tag=nil)
@@ -48,7 +69,7 @@ module Souffle::Provider
48
69
  end
49
70
 
50
71
  # Creates a raid array for a given provider. Intended to be overridden.
51
- #
72
+ #
52
73
  # @raise [Souffle::Exceptions::Provider] This definition must be
53
74
  # overridden.
54
75
  def create_raid
@@ -57,9 +78,9 @@ module Souffle::Provider
57
78
  end
58
79
 
59
80
  # Generates the json required for chef-solo to run on a node.
60
- #
81
+ #
61
82
  # @param [ Souffle::Node ] node The node to generate chef-solo json for.
62
- #
83
+ #
63
84
  # @return [ String ] The chef-solo json for the particular node.
64
85
  def generate_chef_json(node)
65
86
  json_info = Hash.new
@@ -71,7 +92,7 @@ module Souffle::Provider
71
92
 
72
93
  # Waits for ssh to be accessible for a node for the initial connection and
73
94
  # yields an ssh object to manage the commands naturally from there.
74
- #
95
+ #
75
96
  # @param [ String ] address The address of the machine to connect to.
76
97
  # @param [ String ] user The user to connect as.
77
98
  # @param [ String, NilClass ] pass By default publickey and password auth
@@ -83,7 +104,7 @@ module Souffle::Provider
83
104
  # @option opts [ Hash ] :timeout (TIMEOUT) default timeout for all
84
105
  # #wait_for and #send_wait calls.
85
106
  # @option opts [ Boolean ] :reconnect When disconnected reconnect.
86
- #
107
+ #
87
108
  # @yield [ Eventmachine::Ssh:Session ] The ssh session.
88
109
  def wait_for_boot(address, user="root", pass=nil, opts={},
89
110
  timeout=200)
@@ -111,7 +132,7 @@ module Souffle::Provider
111
132
  end
112
133
 
113
134
  # Yields an ssh object to manage the commands naturally from there.
114
- #
135
+ #
115
136
  # @param [ String ] address The address of the machine to connect to.
116
137
  # @param [ String ] user The user to connect as.
117
138
  # @param [ String, NilClass ] pass By default publickey and password auth
@@ -122,7 +143,7 @@ module Souffle::Provider
122
143
  # @option opts [ Hash ] :timeout (TIMEOUT) default timeout for all
123
144
  # #wait_for and #send_wait calls.
124
145
  # @option opts [ Boolean ] :reconnect When disconnected reconnect.
125
- #
146
+ #
126
147
  # @yield [ EventMachine::Ssh::Session ] The ssh session.
127
148
  def ssh_block(address, user="root", pass=nil, opts={})
128
149
  opts[:password] = pass unless pass.nil?
@@ -136,18 +157,18 @@ module Souffle::Provider
136
157
  end
137
158
 
138
159
  # The path to the ssh key with the given name.
139
- #
160
+ #
140
161
  # @param [ String ] key_name The name fo the ssh key to lookup.
141
- #
162
+ #
142
163
  # @return [ String ] The path to the ssh key with the given name.
143
164
  def ssh_key(key_name)
144
165
  "#{ssh_key_path}/#{key_name}"
145
166
  end
146
167
 
147
168
  # Grabs an ssh key for a given aws node.
148
- #
169
+ #
149
170
  # @param [ String ] key_name The name fo the ssh key to lookup.
150
- #
171
+ #
151
172
  # @return [ Boolean ] Whether or not the ssh_key exists
152
173
  # for the node.
153
174
  def ssh_key_exists?(key_name)
@@ -160,11 +181,11 @@ module Souffle::Provider
160
181
  rescue
161
182
  error_msg = "The ssh key directory does not have write permissions: "
162
183
  error_msg << ssh_key_path
163
- raise PermissionErrorSshKeys, error_msg
184
+ raise Souffle::Exceptions::PermissionErrorSshKeys, error_msg
164
185
  end
165
186
 
166
187
  # The path to the ssh keys for the provider.
167
- #
188
+ #
168
189
  # @return [ String ] The path to the ssh keys for the provider.
169
190
  def ssh_key_path
170
191
  File.join(File.dirname(
@@ -172,7 +193,7 @@ module Souffle::Provider
172
193
  end
173
194
 
174
195
  # Rsync's a file to a remote node.
175
- #
196
+ #
176
197
  # @param [ String ] ipaddress The ipaddress of the node to connect to.
177
198
  # @param [ String ] file The file to rsync.
178
199
  # @param [ String ] path The remote path to rsync.
@@ -189,7 +210,7 @@ module Souffle::Provider
189
210
  end
190
211
 
191
212
  # The list of cookbooks and their full paths.
192
- #
213
+ #
193
214
  # @return [ Array ] The list of cookbooks and their full paths.
194
215
  def cookbook_paths
195
216
  Array(Souffle::Config[:chef_cookbook_path]).inject([]) do |_paths, path|
@@ -201,7 +222,7 @@ module Souffle::Provider
201
222
  end
202
223
 
203
224
  # The list of roles and their full paths.
204
- #
225
+ #
205
226
  # @return [ Array ] The list of roles and their full paths.
206
227
  def role_paths
207
228
  Array(Souffle::Config[:chef_role_path]).inject([]) do |_paths, path|
@@ -213,7 +234,7 @@ module Souffle::Provider
213
234
  end
214
235
 
215
236
  # Creates a new cookbook tarball for the deployment.
216
- #
237
+ #
217
238
  # @return [ String ] The path to the created tarball.
218
239
  def create_cookbooks_tarball
219
240
  tarball_name = "cookbooks-latest.tar.gz"
@@ -210,7 +210,7 @@ class Souffle::Provider::AWS < Souffle::Provider::Base
210
210
 
211
211
  pre_event do
212
212
  @partitions = 0
213
- @provider = node.provisioner.provider
213
+ @provider = node.provider
214
214
  node.options[:volumes].each_with_index do |volume, index|
215
215
  @provider.partition_device(
216
216
  node, @provider.volume_id_to_device(index)) do |count|
@@ -284,10 +284,10 @@ class Souffle::Provider::AWS < Souffle::Provider::Base
284
284
  #
285
285
  # @param [ Souffle::Node ] node The node to install mdadm on.
286
286
  def setup_mdadm(node)
287
- ssh_block(node) do |ssh|
287
+ n = node; ssh_block(node) do |ssh|
288
288
  ssh.exec!("/usr/bin/yum install -y mdadm")
289
+ n.provisioner.mdadm_installed
289
290
  end
290
- node.provisioner.mdadm_installed
291
291
  end
292
292
 
293
293
  # Sets up software raid for the given node.
@@ -330,7 +330,7 @@ class Souffle::Provider::AWS < Souffle::Provider::Base
330
330
 
331
331
  pre_event do
332
332
  Souffle::Log.info "#{node.log_prefix} Waiting for node running..."
333
- @provider = node.provisioner.provider
333
+ @provider = node.provider
334
334
  @blk = blk
335
335
  end
336
336
 
@@ -364,7 +364,7 @@ class Souffle::Provider::AWS < Souffle::Provider::Base
364
364
 
365
365
  pre_event do
366
366
  Souffle::Log.info "#{node.log_prefix} Waiting for EBS to be ready..."
367
- @provider = node.provisioner.provider
367
+ @provider = node.provider
368
368
  @volume_ids = node.options[:volumes].map { |v| v[:aws_id] }
369
369
  end
370
370
 
@@ -479,12 +479,11 @@ class Souffle::Provider::AWS < Souffle::Provider::Base
479
479
  # @todo Setup the chef/chef-solo tar gzip and ssh connections.
480
480
  def provision(node)
481
481
  set_hostname(node)
482
- if node.try_opt(:chef_provisioner) == :solo
482
+ if node.try_opt(:chef_provisioner).to_s.downcase == "solo"
483
483
  provision_chef_solo(node, generate_chef_json(node))
484
484
  else
485
485
  provision_chef_client(node)
486
486
  end
487
- node.provisioner.provisioned
488
487
  end
489
488
 
490
489
  # Waits for ssh to be accessible for a node for the initial connection and
@@ -515,7 +514,7 @@ class Souffle::Provider::AWS < Souffle::Provider::Base
515
514
 
516
515
  pre_event do
517
516
  Souffle::Log.info "#{node.log_prefix} Waiting for ssh..."
518
- @provider = node.provisioner.provider
517
+ @provider = node.provider
519
518
  @blk = blk
520
519
  end
521
520
 
@@ -572,7 +571,7 @@ class Souffle::Provider::AWS < Souffle::Provider::Base
572
571
  solo_config = "node_name \"#{node.fqdn}\"\n"
573
572
  solo_config << "cookbook_path \"/tmp/cookbooks\"\n"
574
573
  solo_config << 'role_path "/tmp/roles"'
575
- ssh_block(node) do |ssh|
574
+ n = node; ssh_block(node) do |ssh|
576
575
  ssh.exec!("sleep 2; tar -zxf /tmp/cookbooks-latest.tar.gz -C /tmp")
577
576
  ssh.exec!("echo '#{solo_config}' >/tmp/solo.rb")
578
577
  ssh.exec!("echo '#{solo_json}' >/tmp/solo.json")
@@ -580,6 +579,7 @@ class Souffle::Provider::AWS < Souffle::Provider::Base
580
579
  rm_files = %w{ /tmp/cookbooks /tmp/cookbooks-latest.tar.gz
581
580
  /tmp/roles /tmp/solo.rb /tmp/solo.json /tmp/chef_bootstrap }
582
581
  ssh.exec!("rm -rf #{rm_files}")
582
+ n.provisioner.provisioned
583
583
  end
584
584
  end
585
585
 
@@ -587,8 +587,14 @@ class Souffle::Provider::AWS < Souffle::Provider::Base
587
587
  #
588
588
  # @todo Chef client provisioner needs to be completed.
589
589
  def provision_chef_client(node)
590
- ssh_block(node) do |ssh|
591
- ssh.exec!("chef-client")
590
+ client_cmds = "chef-client -N #{node.fqdn} "
591
+ client_cmds << "-j /tmp/client.json "
592
+ client_cmds << "-S #{node.try_opt(:chef_server)} "
593
+ n = node; ssh_block(node) do |ssh|
594
+ write_temp_chef_json(ssh, n)
595
+ ssh.exec!(client_cmds)
596
+ cleanup_temp_chef_files(ssh, n)
597
+ node.provisioner.provisioned
592
598
  end
593
599
  end
594
600
 
@@ -725,4 +731,23 @@ class Souffle::Provider::AWS < Souffle::Provider::Base
725
731
  end
726
732
  end
727
733
 
734
+ private
735
+
736
+ # Writes a temporary chef-client json file.
737
+ #
738
+ # @param [ EventMachine::Ssh::Connection ] ssh The em-ssh connection.
739
+ # @param [ Souffle::Node ] node The given node to work with.
740
+ def write_temp_chef_json(ssh, node)
741
+ ssh.exec!("echo '''#{generate_chef_json(node)}''' > /tmp/client.json")
742
+ end
743
+
744
+ # Removes the temporary chef-client files.
745
+ #
746
+ # @param [ EventMachine::Ssh::Connection ] ssh The em-ssh connection.
747
+ # @param [ Souffle::Node ] node The given node to work with.
748
+ def cleanup_temp_chef_files(ssh, node)
749
+ ssh.exec!("rm -f /tmp/client.json")
750
+ ssh.exec!("rm -f /etc/chef/validation.pem")
751
+ end
752
+
728
753
  end
@@ -19,6 +19,7 @@ class Souffle::Provisioner::Node
19
19
  after_transition :formatting_device => :ready_to_provision,
20
20
  :do => :ready
21
21
  after_transition any => :provisioning, :do => :provision
22
+ after_transition any => :complete, :do => :node_provisioned
22
23
 
23
24
  event :reclaimed do
24
25
  transition any => :creating
@@ -133,6 +134,12 @@ class Souffle::Provisioner::Node
133
134
  provider.provision(@node)
134
135
  end
135
136
 
137
+ # Notifies the system that the current node has completed provisioning.
138
+ def node_provisioned
139
+ Souffle::Log.info "#{@node.log_prefix} Node provisioned."
140
+ system_provisioner.node_provisioned
141
+ end
142
+
136
143
  # Kills the node entirely.
137
144
  def kill
138
145
  Souffle::Log.info "#{@node.log_prefix} Killing node..."
@@ -152,6 +159,11 @@ class Souffle::Provisioner::Node
152
159
 
153
160
  # Helper function for the node's system provider.
154
161
  def provider
155
- @node.system.provisioner.provider
162
+ @node.provider
163
+ end
164
+
165
+ # Helper function for the system provisioner.
166
+ def system_provisioner
167
+ @node.system.provisioner
156
168
  end
157
169
  end
@@ -13,6 +13,7 @@ class Souffle::Provisioner::System
13
13
  after_transition :initializing => :creating, :do => :create
14
14
  after_transition :creating => :provisioning, :do => :provision
15
15
  after_transition any => :initializing, :do => :create
16
+ after_transition :provisioning => :complete, :do => :system_provisioned
16
17
 
17
18
  event :initialized do
18
19
  transition :initializing => :creating
@@ -51,13 +52,14 @@ class Souffle::Provisioner::System
51
52
  # @param [ Souffle::Provider::Base ] provider The provider to use.
52
53
  # @param [ Fixnum ] max_failures the maximum number of failures.
53
54
  # @param [ Fixnum ] timeout The maximum time to wait for node creation.
54
- def initialize(system, provider, max_failures=3, timeout=500)
55
+ def initialize(system, provider, max_failures=3, timeout=600)
55
56
  @failures = 0
56
57
  @system = system
57
58
  @provider = provider
58
59
  @time_used = 0
59
60
  @timeout = timeout
60
61
  @max_failures = max_failures
62
+ @nodes_completed = 0
61
63
  super() # NOTE: This is here to initialize state_machine.
62
64
  end
63
65
 
@@ -113,12 +115,23 @@ class Souffle::Provisioner::System
113
115
  end
114
116
  end
115
117
 
118
+ # System has completed provisioning.
119
+ def system_provisioned
120
+ Souffle::Log.info "[#{system_tag}] System provisioned."
121
+ end
122
+
123
+ # Updates the number of nodes provisioned for the system provisioner.
124
+ def node_provisioned
125
+ @nodes_completed += 1
126
+ provisioned if @nodes_completed == @system.nodes.size
127
+ end
128
+
116
129
  # Kills the system.
117
130
  def kill_system
118
131
  # @provider.kill(@system.nodes)
119
132
  end
120
133
 
121
- # Handles the error state and recreates the system
134
+ # Handles the error state and recreates the system.
122
135
  def error_handler
123
136
  @failures += 1
124
137
  if @failures >= @max_failures
@@ -169,24 +182,9 @@ class Souffle::Provisioner::System
169
182
 
170
183
  # Wait until all of the nodes are provisioned and then continue.
171
184
  def wait_until_complete
172
- total_nodes = @system.nodes.size
173
- all_complete = false
174
- timer = EM::PeriodicTimer.new(2) do
175
- nodes_ready = @system.nodes.select do |n|
176
- n.provisioner.state == "complete"
177
- end.size
178
-
179
- if nodes_ready == total_nodes
180
- all_complete = true
181
- timer.cancel
182
- created
183
- end
184
- end
185
-
186
185
  EM::Timer.new(@timeout) do
187
- unless all_complete
186
+ unless @nodes_completed == @system.nodes.size
188
187
  Souffle::Log.error "[#{system_tag}] System provision timeout reached."
189
- timer.cancel
190
188
  error_occurred
191
189
  end
192
190
  end
@@ -13,15 +13,9 @@ class Souffle::Server
13
13
  # Runs the server.
14
14
  def run
15
15
  if Souffle::Config[:server]
16
- EM.synchrony do
17
- @app = Rack::Builder.new do
18
- use Rack::Lint
19
- use Rack::ShowExceptions
20
- run Rack::Cascade.new([Souffle::Http])
21
- end.to_app
22
-
23
- Rack::Handler.get(:thin).run(@app, rack_options)
24
- end
16
+ run_server
17
+ else
18
+ run_instance
25
19
  end
26
20
  end
27
21
 
@@ -44,5 +38,26 @@ class Souffle::Server
44
38
  end
45
39
  opts
46
40
  end
41
+
42
+ # Starts a long-running webserver that continuously handles requests.
43
+ def run_server
44
+ EM.synchrony do
45
+ @app = Rack::Builder.new do
46
+ use Rack::Lint
47
+ use Rack::ShowExceptions
48
+ run Rack::Cascade.new([Souffle::Http])
49
+ end.to_app
50
+
51
+ Rack::Handler.get(:thin).run(@app, rack_options)
52
+ end
53
+ end
54
+
55
+ # Starts a single instance of the provisioner.
56
+ def run_instance
57
+ Souffle::Log.info "Single instance runs are not currently implemented..."
58
+ # system = Souffle::System.from_hash(data)
59
+ # provider = Souffle::Provider.plugin(system.try_opt(:provider)).new
60
+ # system_tag = provider.create_system(system)
61
+ end
47
62
 
48
63
  end
@@ -103,6 +103,13 @@ class Souffle::System
103
103
  @nodes.select { |n| n.dependencies.any? }
104
104
  end
105
105
 
106
+ # Returns the current system provider.
107
+ #
108
+ # @return [ Souffle::Provider::Base ] The current system provider.
109
+ def provider
110
+ @provisioner.provider
111
+ end
112
+
106
113
  # Tries to fetch an option parameter otherwise it grabs it from config.
107
114
  #
108
115
  # @param [ Symbol ] opt The option to try and fetch.
@@ -1,6 +1,5 @@
1
1
  # An orchestrator for setting up isolated chef-managed systems.
2
2
  module Souffle
3
3
  # The current souffle version.
4
- VERSION = "0.0.3"
4
+ VERSION = "0.0.4"
5
5
  end
6
-
@@ -53,4 +53,14 @@ describe "Souffle::Provider::Base" do
53
53
 
54
54
  JSON.parse(@provider.generate_chef_json(node)).should eql(runlist)
55
55
  end
56
+
57
+ it "should be able to generate a list of provider plugins" do
58
+ ["base", "vagrant", "aws"].each do |plugin|
59
+ Souffle::Provider.plugins.include?(plugin).should eql(true)
60
+ end
61
+ end
62
+
63
+ it "should be able to select a particular plugin" do
64
+ Souffle::Provider.plugin("aws").should eql(Souffle::Provider::AWS)
65
+ end
56
66
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: souffle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-19 00:00:00.000000000 Z
12
+ date: 2012-09-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: yajl-ruby
@@ -34,7 +34,7 @@ dependencies:
34
34
  requirements:
35
35
  - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: 0.12.10
37
+ version: 1.0.0
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,7 @@ dependencies:
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: 0.12.10
45
+ version: 1.0.0
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: amqp
48
48
  requirement: !ruby/object:Gem::Requirement