spiceweasel 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +28 -11
- data/bin/spiceweasel +18 -14
- data/lib/spiceweasel/cookbook_list.rb +14 -15
- data/lib/spiceweasel/data_bag_list.rb +7 -7
- data/lib/spiceweasel/directory_extractor.rb +9 -9
- data/lib/spiceweasel/environment_list.rb +7 -7
- data/lib/spiceweasel/node_list.rb +11 -11
- data/lib/spiceweasel/role_list.rb +10 -10
- data/lib/spiceweasel/version.rb +1 -1
- metadata +8 -8
data/README.md
CHANGED
@@ -12,7 +12,7 @@ Requirements
|
|
12
12
|
============
|
13
13
|
Spiceweasel currently depends on `knife` to run commands for it, but does not explicitly depend on the `chef` gem yet. Infrastructure files must either end in .json or .yml to be processed.
|
14
14
|
|
15
|
-
Written and tested initially with Chef 0.9.12 (should still work) and continuing development with the
|
15
|
+
Written and tested initially with Chef 0.9.12 (should still work) and continuing development with the 10. series. It is tested with Ruby 1.8.7 and 1.9.2.
|
16
16
|
|
17
17
|
File Syntax
|
18
18
|
===========
|
@@ -43,7 +43,7 @@ data bags:
|
|
43
43
|
- bob
|
44
44
|
- chuck
|
45
45
|
- data:
|
46
|
-
- *
|
46
|
+
- "*"
|
47
47
|
- passwords:
|
48
48
|
- secret secret_key
|
49
49
|
- mysql
|
@@ -60,7 +60,7 @@ nodes:
|
|
60
60
|
- -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small
|
61
61
|
- rackspace 3:
|
62
62
|
- recipe[mysql],role[monitoring]
|
63
|
-
- --image 49 --flavor 2
|
63
|
+
- --image 49 --flavor 2 --node-name rs{{n}}.example.com
|
64
64
|
- windows_winrm winboxA:
|
65
65
|
- role[base],role[iisserver]
|
66
66
|
- -x Administrator -P 'super_secret_password'
|
@@ -143,7 +143,7 @@ From the `example.json`:
|
|
143
143
|
{"rackspace 3":
|
144
144
|
[
|
145
145
|
"recipe[mysql],role[monitoring]",
|
146
|
-
"--image 49 --flavor 2"
|
146
|
+
"--image 49 --flavor 2 --node-name rs{{n}}.example.com"
|
147
147
|
]
|
148
148
|
},
|
149
149
|
{"windows_winrm winboxA":
|
@@ -225,7 +225,7 @@ knife role from file webserver.rb
|
|
225
225
|
|
226
226
|
Data Bags
|
227
227
|
---------
|
228
|
-
The `data bags` section of the manifest currently creates the data bags listed with `knife data bag create FOO` where `FOO` is the name of the data bag. Individual items may be added to the data bag as part of a JSON or YAML sequence, the assumption is made that they `.json` files and in the proper `data_bags/FOO` directory. You may also pass a wildcard as an entry to load all matching data bags (ie.
|
228
|
+
The `data bags` section of the manifest currently creates the data bags listed with `knife data bag create FOO` where `FOO` is the name of the data bag. Individual items may be added to the data bag as part of a JSON or YAML sequence, the assumption is made that they `.json` files and in the proper `data_bags/FOO` directory. You may also pass a wildcard as an entry to load all matching data bags (ie. `"*"`). Encrypted data bags are supported by listing `secret filename` as the first item (where `filename` is the secret key to be used). Validation is done to ensure the JSON is properly formatted, the id matches and any secret keys are in the correct locations. Assuming the presence of `dataA.json` and `dataB.json` in the `data_bags/data` directory, the YAML snippet
|
229
229
|
|
230
230
|
``` yaml
|
231
231
|
data bags:
|
@@ -234,7 +234,7 @@ data bags:
|
|
234
234
|
- bob
|
235
235
|
- chuck
|
236
236
|
- data:
|
237
|
-
- *
|
237
|
+
- "*"
|
238
238
|
- passwords:
|
239
239
|
- secret secret_key
|
240
240
|
- mysql
|
@@ -258,7 +258,7 @@ knife data bag from file passwords rabbitmq.json --secret-file secret_key
|
|
258
258
|
|
259
259
|
Nodes
|
260
260
|
-----
|
261
|
-
The `nodes` section of the manifest bootstraps a node for each entry where the entry is a hostname or provider and count. A shortcut syntax for bulk-creating nodes with various providers where the line starts with the provider and ends with the number of nodes to be provisioned. Windows nodes need to specify either `windows_winrm` or `windows_ssh` depending on the protocol used, followed by the name of the node(s). Each node requires 2 items after it in a sequence. You may also use the `--parallel` flag from the command line, allowing provider commands to run simultaneously for faster deployment.
|
261
|
+
The `nodes` section of the manifest bootstraps a node for each entry where the entry is a hostname or provider and count. A shortcut syntax for bulk-creating nodes with various providers where the line starts with the provider and ends with the number of nodes to be provisioned. Windows nodes need to specify either `windows_winrm` or `windows_ssh` depending on the protocol used, followed by the name of the node(s). Each node requires 2 items after it in a sequence. You may also use the `--parallel` flag from the command line, allowing provider commands to run simultaneously for faster deployment. If you want to give your nodes names, simply pass `-N NAME{{n}}` or `--node-name NAME{{n}}` and the `{{n}}` will be substituted by a number (works with or without --parallel).
|
262
262
|
|
263
263
|
The first item after the node is the run_list and the second are the CLI options used. The run_list may be space or comma-delimited. Validation is performed on the run_list components to ensure that only cookbooks and roles listed in the manifest are used. Validation on the options ensures that any Environments referenced are also listed. You may specify multiple nodes to have the same configuration by listing them separated by a space. The example YAML snippet
|
264
264
|
|
@@ -275,7 +275,7 @@ nodes:
|
|
275
275
|
- -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small
|
276
276
|
- rackspace 3:
|
277
277
|
- recipe[mysql],role[monitoring]
|
278
|
-
- --image 49 --flavor 2
|
278
|
+
- --image 49 --flavor 2 --node-name rs{{n}}.example.com
|
279
279
|
- windows_winrm winboxA:
|
280
280
|
- role[base],role[iisserver]
|
281
281
|
- -x Administrator -P 'super_secret_password'
|
@@ -294,14 +294,31 @@ knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7
|
|
294
294
|
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -r 'role[webserver],recipe[mysql::client]'
|
295
295
|
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -r 'role[webserver],recipe[mysql::client]'
|
296
296
|
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -r 'role[webserver],recipe[mysql::client]'
|
297
|
-
knife rackspace server create --image 49 --flavor 2 -r 'recipe[mysql],role[monitoring]'
|
298
|
-
knife rackspace server create --image 49 --flavor 2 -r 'recipe[mysql],role[monitoring]'
|
299
|
-
knife rackspace server create --image 49 --flavor 2 -r 'recipe[mysql],role[monitoring]'
|
297
|
+
knife rackspace server create --image 49 --flavor 2 --node-name rs1.example.com -r 'recipe[mysql],role[monitoring]'
|
298
|
+
knife rackspace server create --image 49 --flavor 2 --node-name rs2.example.com -r 'recipe[mysql],role[monitoring]'
|
299
|
+
knife rackspace server create --image 49 --flavor 2 --node-name rs3.example.com -r 'recipe[mysql],role[monitoring]'
|
300
300
|
knife bootstrap windows winrm winboxA -x Administrator -P 'super_secret_password' -r 'role[base],role[iisserver]'
|
301
301
|
knife bootstrap windows ssh winboxB -x Administrator -P 'super_secret_password' -r 'role[base],role[iisserver]'
|
302
302
|
knife bootstrap windows ssh winboxC -x Administrator -P 'super_secret_password' -r 'role[base],role[iisserver]'
|
303
303
|
```
|
304
304
|
|
305
|
+
Using `--parallel` with the following block and the `-N webserver{{n}}`
|
306
|
+
|
307
|
+
``` yaml
|
308
|
+
nodes:
|
309
|
+
- ec2 3:
|
310
|
+
- role[webserver]
|
311
|
+
- -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -N webserver{{n}}
|
312
|
+
```
|
313
|
+
|
314
|
+
produces the following:
|
315
|
+
|
316
|
+
```
|
317
|
+
seq 3 | parallel -j 0 -v "knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -N webserver{} -r 'role[base],role[tc],role[users]'"
|
318
|
+
```
|
319
|
+
|
320
|
+
which generates nodes named "webserver1", "webserver2" and "webserver3".
|
321
|
+
|
305
322
|
Extract
|
306
323
|
=======
|
307
324
|
Spiceweasel may also be used to generate knife commands or Spiceweasel manifests in JSON or YAML.
|
data/bin/spiceweasel
CHANGED
@@ -30,13 +30,13 @@ begin
|
|
30
30
|
ARGV << "-h" if ARGV.empty?
|
31
31
|
cli = Spiceweasel::CLI.new
|
32
32
|
cli.parse_options
|
33
|
-
DEBUG = cli.config[:debug]
|
34
|
-
PARALLEL = cli.config[:parallel]
|
35
|
-
SITEINSTALL = cli.config[:siteinstall]
|
36
|
-
NOVALIDATION = cli.config[:novalidation]
|
37
|
-
EXTRACTLOCAL = cli.config[:extractlocal]
|
38
|
-
EXTRACTYAML = cli.config[:extractyaml]
|
39
|
-
EXTRACTJSON = cli.config[:extractjson]
|
33
|
+
Spiceweasel::DEBUG = cli.config[:debug]
|
34
|
+
Spiceweasel::PARALLEL = cli.config[:parallel]
|
35
|
+
Spiceweasel::SITEINSTALL = cli.config[:siteinstall]
|
36
|
+
Spiceweasel::NOVALIDATION = cli.config[:novalidation]
|
37
|
+
Spiceweasel::EXTRACTLOCAL = cli.config[:extractlocal]
|
38
|
+
Spiceweasel::EXTRACTYAML = cli.config[:extractyaml]
|
39
|
+
Spiceweasel::EXTRACTJSON = cli.config[:extractjson]
|
40
40
|
rescue OptionParser::InvalidOption => e
|
41
41
|
STDERR.puts e.message
|
42
42
|
puts cli.opt_parser.to_s
|
@@ -51,13 +51,13 @@ if cli.config[:serverurl]
|
|
51
51
|
options['knife_options'] += " --server-url " + cli.config[:serverurl]
|
52
52
|
end
|
53
53
|
|
54
|
-
if EXTRACTLOCAL || EXTRACTJSON || EXTRACTYAML
|
54
|
+
if Spiceweasel::EXTRACTLOCAL || Spiceweasel::EXTRACTJSON || Spiceweasel::EXTRACTYAML
|
55
55
|
input = Spiceweasel::DirectoryExtractor.parse_objects
|
56
|
-
STDOUT.puts "DEBUG: extract input: #{input}" if DEBUG
|
56
|
+
STDOUT.puts "DEBUG: extract input: #{input}" if Spiceweasel::DEBUG
|
57
57
|
else
|
58
58
|
begin
|
59
59
|
file = ARGV.last
|
60
|
-
STDOUT.puts "DEBUG: file: #{file}" if DEBUG
|
60
|
+
STDOUT.puts "DEBUG: file: #{file}" if Spiceweasel::DEBUG
|
61
61
|
if (file.end_with?(".yml"))
|
62
62
|
input = YAML.load_file ARGV.last
|
63
63
|
elsif (file.end_with?(".json"))
|
@@ -66,16 +66,20 @@ else
|
|
66
66
|
STDERR.puts "ERROR: Unknown file type, please use a file ending with either '.json' or '.yml'."
|
67
67
|
exit(-1)
|
68
68
|
end
|
69
|
+
rescue Psych::SyntaxError => e
|
70
|
+
STDERR.puts e.message
|
71
|
+
STDERR.puts "ERROR: Parsing error in #{file}."
|
72
|
+
exit(-1)
|
69
73
|
rescue JSON::ParserError => e
|
70
74
|
STDERR.puts e.message
|
71
|
-
STDERR.puts "ERROR: Parsing error in
|
75
|
+
STDERR.puts "ERROR: Parsing error in #{file}."
|
72
76
|
exit(-1)
|
73
77
|
rescue Exception
|
74
78
|
STDERR.puts "ERROR: No infrastructure .json or .yml file provided."
|
75
79
|
puts cli.opt_parser.to_s
|
76
80
|
exit(-1)
|
77
81
|
end
|
78
|
-
STDOUT.puts "DEBUG: file input: #{input}" if DEBUG
|
82
|
+
STDOUT.puts "DEBUG: file input: #{input}" if Spiceweasel::DEBUG
|
79
83
|
end
|
80
84
|
|
81
85
|
create = String.new()
|
@@ -107,9 +111,9 @@ elsif cli.config[:rebuild]
|
|
107
111
|
puts delete unless delete.empty?
|
108
112
|
puts create unless create.empty?
|
109
113
|
else
|
110
|
-
if EXTRACTJSON
|
114
|
+
if Spiceweasel::EXTRACTJSON
|
111
115
|
puts JSON.pretty_generate(input)
|
112
|
-
elsif EXTRACTYAML
|
116
|
+
elsif Spiceweasel::EXTRACTYAML
|
113
117
|
puts input.to_yaml
|
114
118
|
else
|
115
119
|
puts create unless create.empty?
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Matt Ray (<matt@opscode.com>)
|
3
3
|
#
|
4
|
-
# Copyright:: 2011, Opscode, Inc <legal@opscode.com>
|
4
|
+
# Copyright:: 2011-2012, Opscode, Inc <legal@opscode.com>
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
@@ -29,12 +29,12 @@ class Spiceweasel::CookbookList
|
|
29
29
|
version = cookbook[cb][0].to_s || ""
|
30
30
|
args = cookbook[cb][1] || ""
|
31
31
|
end
|
32
|
-
STDOUT.puts "DEBUG: cookbook: #{cb} #{version}" if DEBUG
|
32
|
+
STDOUT.puts "DEBUG: cookbook: #{cb} #{version}" if Spiceweasel::DEBUG
|
33
33
|
if File.directory?("cookbooks")
|
34
34
|
if File.directory?("cookbooks/#{cb}")
|
35
|
-
validateMetadata(cb,version) unless NOVALIDATION
|
35
|
+
validateMetadata(cb,version) unless Spiceweasel::NOVALIDATION
|
36
36
|
else
|
37
|
-
if SITEINSTALL #use knife cookbook site install
|
37
|
+
if Spiceweasel::SITEINSTALL #use knife cookbook site install
|
38
38
|
@create += "knife cookbook#{options['knife_options']} site install #{cb} #{version} #{args}\n"
|
39
39
|
else #use knife cookbook site download, untar and then remove the tarball
|
40
40
|
@create += "knife cookbook#{options['knife_options']} site download #{cb} #{version} --file cookbooks/#{cb}.tgz #{args}\n"
|
@@ -43,14 +43,14 @@ class Spiceweasel::CookbookList
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
else
|
46
|
-
STDERR.puts "'cookbooks' directory not found, unable to validate, download and load cookbooks" unless NOVALIDATION
|
46
|
+
STDERR.puts "'cookbooks' directory not found, unable to validate, download and load cookbooks" unless Spiceweasel::NOVALIDATION
|
47
47
|
end
|
48
48
|
@create += "knife cookbook#{options['knife_options']} upload #{cb}\n"
|
49
|
-
@delete += "knife cookbook#{options['knife_options']} delete #{cb} #{version} -y\n"
|
49
|
+
@delete += "knife cookbook#{options['knife_options']} delete #{cb} #{version} -a -y\n"
|
50
50
|
|
51
51
|
@cookbook_list[cb] = version
|
52
52
|
end
|
53
|
-
validateDependencies() unless NOVALIDATION
|
53
|
+
validateDependencies() unless Spiceweasel::NOVALIDATION
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -58,29 +58,28 @@ class Spiceweasel::CookbookList
|
|
58
58
|
def validateMetadata(cookbook,version)
|
59
59
|
#check metadata.rb for requested version
|
60
60
|
metadata = File.open("cookbooks/#{cookbook}/metadata.rb").grep(/^version/)[0].split()[1].gsub(/"/,'').to_s
|
61
|
-
STDOUT.puts "DEBUG: cookbook metadata version: #{metadata}" if DEBUG
|
61
|
+
STDOUT.puts "DEBUG: cookbook metadata version: #{metadata}" if Spiceweasel::DEBUG
|
62
62
|
if version and (metadata != version)
|
63
63
|
STDERR.puts "ERROR: Invalid version '#{version}' of '#{cookbook}' requested, '#{metadata}' is already in the cookbooks directory."
|
64
64
|
exit(-1)
|
65
65
|
end
|
66
66
|
deps = File.open("cookbooks/#{cookbook}/metadata.rb").grep(/^depends/)
|
67
67
|
deps.each do |dependency|
|
68
|
-
STDOUT.puts "DEBUG: cookbook #{cookbook} metadata dependency: #{dependency}" if DEBUG
|
68
|
+
STDOUT.puts "DEBUG: cookbook #{cookbook} metadata dependency: #{dependency}" if Spiceweasel::DEBUG
|
69
69
|
line = dependency.split()
|
70
|
-
|
71
|
-
|
72
|
-
cbdep = line[1].gsub(/"/,'')
|
70
|
+
if line[1] =~ /^["']/ #ignore variables and versions
|
71
|
+
cbdep = line[1].gsub(/["']/,'')
|
73
72
|
cbdep.gsub!(/\,/,'') if cbdep.end_with?(',')
|
73
|
+
STDOUT.puts "DEBUG: cookbook #{cookbook} metadata depends: #{cbdep}" if Spiceweasel::DEBUG
|
74
|
+
@dependencies << cbdep
|
74
75
|
end
|
75
|
-
STDOUT.puts "DEBUG: cookbook #{cookbook} metadata depends: #{cbdep}" if DEBUG
|
76
|
-
@dependencies << cbdep
|
77
76
|
end
|
78
77
|
return @cookbook
|
79
78
|
end
|
80
79
|
|
81
80
|
#compare the list of cookbook deps with those specified
|
82
81
|
def validateDependencies()
|
83
|
-
STDOUT.puts "DEBUG: cookbook validateDependencies: '#{@dependencies}'" if DEBUG
|
82
|
+
STDOUT.puts "DEBUG: cookbook validateDependencies: '#{@dependencies}'" if Spiceweasel::DEBUG
|
84
83
|
@dependencies.each do |dep|
|
85
84
|
if !member?(dep)
|
86
85
|
STDERR.puts "ERROR: Cookbook dependency '#{dep}' is missing from the list of cookbooks in the manifest."
|
@@ -23,23 +23,23 @@ class Spiceweasel::DataBagList
|
|
23
23
|
@create = @delete = ''
|
24
24
|
if data_bags
|
25
25
|
if !File.directory?("data_bags")
|
26
|
-
STDERR.puts "ERROR: 'data_bags' directory not found, unable to validate or load data bag items" unless NOVALIDATION
|
26
|
+
STDERR.puts "ERROR: 'data_bags' directory not found, unable to validate or load data bag items" unless Spiceweasel::NOVALIDATION
|
27
27
|
end
|
28
28
|
data_bags.each do |data_bag|
|
29
29
|
db = data_bag.keys[0]
|
30
|
-
STDOUT.puts "DEBUG: data bag: #{db}" if DEBUG
|
30
|
+
STDOUT.puts "DEBUG: data bag: #{db}" if Spiceweasel::DEBUG
|
31
31
|
if !File.directory?("data_bags/#{db}")
|
32
|
-
STDERR.puts "ERROR: 'data_bags/#{db}' directory not found, unable to validate or load data bag items" unless NOVALIDATION
|
32
|
+
STDERR.puts "ERROR: 'data_bags/#{db}' directory not found, unable to validate or load data bag items" unless Spiceweasel::NOVALIDATION
|
33
33
|
end
|
34
34
|
@create += "knife data bag#{options['knife_options']} create #{db}\n"
|
35
35
|
@delete += "knife data bag#{options['knife_options']} delete #{db} -y\n"
|
36
36
|
items = data_bag[db] || []
|
37
37
|
secret = nil
|
38
38
|
while item = items.shift
|
39
|
-
STDOUT.puts "DEBUG: data bag #{db} item: #{item}" if DEBUG
|
39
|
+
STDOUT.puts "DEBUG: data bag #{db} item: #{item}" if Spiceweasel::DEBUG
|
40
40
|
if item.start_with?("secret")
|
41
41
|
secret = item.split()[1]
|
42
|
-
if !File.exists?(secret) and !NOVALIDATION
|
42
|
+
if !File.exists?(secret) and !Spiceweasel::NOVALIDATION
|
43
43
|
STDERR.puts "ERROR: secret key #{secret} not found, unable to load encrypted data bags for data bag #{db}."
|
44
44
|
exit(-1)
|
45
45
|
end
|
@@ -48,10 +48,10 @@ class Spiceweasel::DataBagList
|
|
48
48
|
if item =~ /\*/ #wildcard support, will fail if directory not present
|
49
49
|
files = Dir.glob("data_bags/#{db}/#{item}.json")
|
50
50
|
items += files.collect {|x| x[x.rindex('/')+1..-6]}
|
51
|
-
STDOUT.puts "DEBUG: found items '#{items}' for data bag: #{db}" if DEBUG
|
51
|
+
STDOUT.puts "DEBUG: found items '#{items}' for data bag: #{db}" if Spiceweasel::DEBUG
|
52
52
|
next
|
53
53
|
end
|
54
|
-
validateItem(db, item) unless NOVALIDATION
|
54
|
+
validateItem(db, item) unless Spiceweasel::NOVALIDATION
|
55
55
|
if secret
|
56
56
|
@create += "knife data bag#{options['knife_options']} from file #{db} #{item}.json --secret-file #{secret}\n"
|
57
57
|
else
|
@@ -25,13 +25,13 @@ class Spiceweasel::DirectoryExtractor
|
|
25
25
|
cookbooks = []
|
26
26
|
Dir.glob("cookbooks/*").each do |cookbook_full_path|
|
27
27
|
cookbook = cookbook_full_path.split('/').last
|
28
|
-
STDOUT.puts "DEBUG: dir_ext: cookbook: '#{cookbook}'" if DEBUG
|
28
|
+
STDOUT.puts "DEBUG: dir_ext: cookbook: '#{cookbook}'" if Spiceweasel::DEBUG
|
29
29
|
cookbook_data = Spiceweasel::CookbookData.new(cookbook)
|
30
30
|
if cookbook_data.is_readable?
|
31
31
|
cookbooks << cookbook_data.read
|
32
32
|
end
|
33
33
|
end
|
34
|
-
STDOUT.puts "DEBUG: dir_ext: cookbooks: '#{cookbooks}'" if DEBUG
|
34
|
+
STDOUT.puts "DEBUG: dir_ext: cookbooks: '#{cookbooks}'" if Spiceweasel::DEBUG
|
35
35
|
cookbooks = self.order_cookbooks_by_dependency(cookbooks)
|
36
36
|
objects["cookbooks"] = cookbooks unless cookbooks.empty?
|
37
37
|
|
@@ -39,7 +39,7 @@ class Spiceweasel::DirectoryExtractor
|
|
39
39
|
roles = []
|
40
40
|
Dir.glob("roles/*.{rb,json}").each do |role_full_path|
|
41
41
|
role = self.grab_name_from_path(role_full_path)
|
42
|
-
STDOUT.puts "DEBUG: dir_ext: role: '#{role}'" if DEBUG
|
42
|
+
STDOUT.puts "DEBUG: dir_ext: role: '#{role}'" if Spiceweasel::DEBUG
|
43
43
|
roles << {role => nil}
|
44
44
|
end
|
45
45
|
objects["roles"] = roles unless roles.nil?
|
@@ -47,7 +47,7 @@ class Spiceweasel::DirectoryExtractor
|
|
47
47
|
environments = []
|
48
48
|
Dir.glob("environments/*.{rb,json}").each do |environment_full_path|
|
49
49
|
environment = self.grab_name_from_path(environment_full_path)
|
50
|
-
STDOUT.puts "DEBUG: dir_ext: environment: '#{environment}'" if DEBUG
|
50
|
+
STDOUT.puts "DEBUG: dir_ext: environment: '#{environment}'" if Spiceweasel::DEBUG
|
51
51
|
environments << {environment => nil}
|
52
52
|
end
|
53
53
|
objects["environments"] = environments unless environments.empty?
|
@@ -55,10 +55,10 @@ class Spiceweasel::DirectoryExtractor
|
|
55
55
|
data_bags = []
|
56
56
|
Dir.glob("data_bags/*").each do |data_bag_full_path|
|
57
57
|
data_bag = data_bag_full_path.split('/').last
|
58
|
-
STDOUT.puts "DEBUG: dir_ext: data_bag: '#{data_bag}'" if DEBUG
|
58
|
+
STDOUT.puts "DEBUG: dir_ext: data_bag: '#{data_bag}'" if Spiceweasel::DEBUG
|
59
59
|
data_bag_items = []
|
60
60
|
Dir.glob("#{data_bag_full_path}/*.{rb,json}").each do |data_bag_item_full_path|
|
61
|
-
STDOUT.puts "DEBUG: dir_ext: data_bag: '#{data_bag}':'#{data_bag_item_full_path}'" if DEBUG
|
61
|
+
STDOUT.puts "DEBUG: dir_ext: data_bag: '#{data_bag}':'#{data_bag_item_full_path}'" if Spiceweasel::DEBUG
|
62
62
|
data_bag_items << self.grab_name_from_path(data_bag_item_full_path)
|
63
63
|
end if File.directory?(data_bag_full_path)
|
64
64
|
data_bags << {data_bag => data_bag_items} unless data_bag_items.empty?
|
@@ -102,12 +102,12 @@ class Spiceweasel::DirectoryExtractor
|
|
102
102
|
unsorted_cookbooks.push(cookbook)
|
103
103
|
scount = scount + 1
|
104
104
|
end
|
105
|
-
STDOUT.puts "DEBUG: dir_ext: sorted_cookbooks: '#{sorted_cookbooks}' #{scount}" if DEBUG
|
105
|
+
STDOUT.puts "DEBUG: dir_ext: sorted_cookbooks: '#{sorted_cookbooks}' #{scount}" if Spiceweasel::DEBUG
|
106
106
|
end
|
107
107
|
if scount > 0
|
108
108
|
remainders = unsorted_cookbooks.collect {|x| x['name']}
|
109
|
-
STDOUT.puts "DEBUG: dir_ext: remainders: '#{remainders}'" if DEBUG
|
110
|
-
if NOVALIDATION #stuff is missing, oh well
|
109
|
+
STDOUT.puts "DEBUG: dir_ext: remainders: '#{remainders}'" if Spiceweasel::DEBUG
|
110
|
+
if Spiceweasel::NOVALIDATION #stuff is missing, oh well
|
111
111
|
sorted_cookbooks.push(remainders).flatten!
|
112
112
|
else
|
113
113
|
deps = unsorted_cookbooks.collect {|x| x['dependencies'].collect {|x| x['cookbook']} - sorted_cookbooks}
|
@@ -25,11 +25,11 @@ class Spiceweasel::EnvironmentList
|
|
25
25
|
if environments
|
26
26
|
environments.each do |env|
|
27
27
|
environment = env.keys[0]
|
28
|
-
STDOUT.puts "DEBUG: environment: #{environment}" if DEBUG
|
28
|
+
STDOUT.puts "DEBUG: environment: #{environment}" if Spiceweasel::DEBUG
|
29
29
|
if File.directory?("environments")
|
30
|
-
validate(environment, cookbooks) unless NOVALIDATION
|
30
|
+
validate(environment, cookbooks) unless Spiceweasel::NOVALIDATION
|
31
31
|
else
|
32
|
-
STDERR.puts "'environments' directory not found, unable to validate or load environments" unless NOVALIDATION
|
32
|
+
STDERR.puts "'environments' directory not found, unable to validate or load environments" unless Spiceweasel::NOVALIDATION
|
33
33
|
end
|
34
34
|
if File.exists?("environments/#{environment}.json")
|
35
35
|
@create += "knife environment#{options['knife_options']} from file #{environment}.json\n"
|
@@ -56,7 +56,7 @@ class Spiceweasel::EnvironmentList
|
|
56
56
|
envcookbooks = File.open("environments/#{environment}.rb").grep(/^cookbook /)
|
57
57
|
envcookbooks.each do |cb|
|
58
58
|
dep = cb.split()[1].gsub(/"/,'').gsub(/,/,'')
|
59
|
-
STDOUT.puts "DEBUG: environment: '#{environment}' cookbook: '#{dep}'" if DEBUG
|
59
|
+
STDOUT.puts "DEBUG: environment: '#{environment}' cookbook: '#{dep}'" if Spiceweasel::DEBUG
|
60
60
|
if !cookbooks.member?(dep)
|
61
61
|
STDERR.puts "ERROR: Cookbook dependency '#{dep}' from environment '#{environment}' is missing from the list of cookbooks in the manifest."
|
62
62
|
exit(-1)
|
@@ -67,16 +67,16 @@ class Spiceweasel::EnvironmentList
|
|
67
67
|
f = File.read("environments/#{environment}.json")
|
68
68
|
JSON.create_id = nil
|
69
69
|
envfile = JSON.parse(f, {:symbolize_names => false})
|
70
|
-
STDOUT.puts "DEBUG: environment: '#{environment}' file: '#{envfile}'" if DEBUG
|
70
|
+
STDOUT.puts "DEBUG: environment: '#{environment}' file: '#{envfile}'" if Spiceweasel::DEBUG
|
71
71
|
#validate that the name inside the file matches
|
72
|
-
STDOUT.puts "DEBUG: environment: '#{environment}' name: '#{envfile['name']}'" if DEBUG
|
72
|
+
STDOUT.puts "DEBUG: environment: '#{environment}' name: '#{envfile['name']}'" if Spiceweasel::DEBUG
|
73
73
|
if !environment.eql?(envfile['name'])
|
74
74
|
STDERR.puts "ERROR: Environment '#{environment}' listed in the manifest does not match the name '#{envfile['name']}' within the 'environments/#{environment}.json' file."
|
75
75
|
exit(-1)
|
76
76
|
end
|
77
77
|
#validate the cookbooks exist if they're mentioned
|
78
78
|
envfile['cookbook_versions'].keys.each do |cb|
|
79
|
-
STDOUT.puts "DEBUG: environment: '#{environment}' cookbook: '#{cb}'" if DEBUG
|
79
|
+
STDOUT.puts "DEBUG: environment: '#{environment}' cookbook: '#{cb}'" if Spiceweasel::DEBUG
|
80
80
|
if !cookbooks.member?(cb.to_s)
|
81
81
|
STDERR.puts "ERROR: Cookbook dependency '#{cb}' from environment '#{environment}' is missing from the list of cookbooks in the manifest."
|
82
82
|
exit(-1)
|
@@ -4,14 +4,14 @@ class Spiceweasel::NodeList
|
|
4
4
|
if nodes
|
5
5
|
nodes.each do |node|
|
6
6
|
nname = node.keys[0]
|
7
|
-
STDOUT.puts "DEBUG: node: '#{nname}'" if DEBUG
|
7
|
+
STDOUT.puts "DEBUG: node: '#{nname}'" if Spiceweasel::DEBUG
|
8
8
|
#convert spaces to commas, drop multiple commas
|
9
9
|
run_list = node[nname][0].gsub(/ /,',').gsub(/,+/,',')
|
10
|
-
STDOUT.puts "DEBUG: node: 'node[nname]' run_list: '#{run_list}'" if DEBUG
|
11
|
-
validateRunList(nname, run_list, cookbooks, roles) unless NOVALIDATION
|
10
|
+
STDOUT.puts "DEBUG: node: 'node[nname]' run_list: '#{run_list}'" if Spiceweasel::DEBUG
|
11
|
+
validateRunList(nname, run_list, cookbooks, roles) unless Spiceweasel::NOVALIDATION
|
12
12
|
noptions = node[nname][1]
|
13
|
-
STDOUT.puts "DEBUG: node: 'node[nname]' options: '#{noptions}'" if DEBUG
|
14
|
-
validateOptions(nname, noptions, environments) unless NOVALIDATION
|
13
|
+
STDOUT.puts "DEBUG: node: 'node[nname]' options: '#{noptions}'" if Spiceweasel::DEBUG
|
14
|
+
validateOptions(nname, noptions, environments) unless Spiceweasel::NOVALIDATION
|
15
15
|
#provider support
|
16
16
|
if nname.start_with?("bluebox ","clodo ","cs ","ec2 ","gandi ","hp ","openstack ","rackspace ","slicehost ","terremark ","voxel ")
|
17
17
|
provider = nname.split()
|
@@ -19,15 +19,15 @@ class Spiceweasel::NodeList
|
|
19
19
|
if (provider.length == 2)
|
20
20
|
count = provider[1]
|
21
21
|
end
|
22
|
-
if PARALLEL
|
22
|
+
if Spiceweasel::PARALLEL
|
23
23
|
@create += "seq #{count} | parallel -j 0 -v \""
|
24
|
-
@create += "knife #{provider[0]}#{options['knife_options']} server create #{noptions}"
|
24
|
+
@create += "knife #{provider[0]}#{options['knife_options']} server create #{noptions}".gsub(/\{\{n\}\}/, '{}')
|
25
25
|
if run_list.length > 0
|
26
26
|
@create += " -r '#{run_list}'\"\n"
|
27
27
|
end
|
28
28
|
else
|
29
|
-
count.to_i.times do
|
30
|
-
@create += "knife #{provider[0]}#{options['knife_options']} server create #{noptions}"
|
29
|
+
count.to_i.times do |i|
|
30
|
+
@create += "knife #{provider[0]}#{options['knife_options']} server create #{noptions}".gsub(/\{\{n\}\}/, (i + 1).to_s)
|
31
31
|
if run_list.length > 0
|
32
32
|
@create += " -r '#{run_list}'\n"
|
33
33
|
end
|
@@ -46,8 +46,8 @@ class Spiceweasel::NodeList
|
|
46
46
|
end
|
47
47
|
@delete += "knife node#{options['knife_options']} list | xargs knife #{provider[0]} server delete -y\n"
|
48
48
|
else #node bootstrap support
|
49
|
-
nname.split.
|
50
|
-
@create += "knife bootstrap#{options['knife_options']} #{server} #{noptions}"
|
49
|
+
nname.split.each_with_index do |server, i|
|
50
|
+
@create += "knife bootstrap#{options['knife_options']} #{server} #{noptions}".gsub(/\{\{n\}\}/, (i + 1).to_s)
|
51
51
|
if run_list.length > 0
|
52
52
|
@create += " -r '#{run_list}'\n"
|
53
53
|
end
|
@@ -25,11 +25,11 @@ class Spiceweasel::RoleList
|
|
25
25
|
if roles
|
26
26
|
flatroles = roles.collect {|x| x.keys}.flatten
|
27
27
|
flatroles.each do |role|
|
28
|
-
STDOUT.puts "DEBUG: role: #{role}" if DEBUG
|
28
|
+
STDOUT.puts "DEBUG: role: #{role}" if Spiceweasel::DEBUG
|
29
29
|
if File.directory?("roles")
|
30
|
-
validate(role, environments, cookbooks, flatroles) unless NOVALIDATION
|
30
|
+
validate(role, environments, cookbooks, flatroles) unless Spiceweasel::NOVALIDATION
|
31
31
|
else
|
32
|
-
STDERR.puts "ERROR: 'roles' directory not found, unable to validate or load roles" unless NOVALIDATION
|
32
|
+
STDERR.puts "ERROR: 'roles' directory not found, unable to validate or load roles" unless Spiceweasel::NOVALIDATION
|
33
33
|
end
|
34
34
|
if File.exists?("roles/#{role}.json")
|
35
35
|
@create += "knife role#{options['knife_options']} from file #{role}.json\n"
|
@@ -48,7 +48,7 @@ class Spiceweasel::RoleList
|
|
48
48
|
if File.exists?("roles/#{role}.rb")
|
49
49
|
#validate that the name inside the file matches
|
50
50
|
name = File.open("roles/#{role}.rb").grep(/^name/)[0].split()[1].gsub(/"/,'').to_s
|
51
|
-
STDOUT.puts "DEBUG: role: '#{role}' name: '#{name}'" if DEBUG
|
51
|
+
STDOUT.puts "DEBUG: role: '#{role}' name: '#{name}'" if Spiceweasel::DEBUG
|
52
52
|
if !role.eql?(name)
|
53
53
|
STDERR.puts "ERROR: Role '#{role}' listed in the manifest does not match the name '#{name}' within the roles/#{role}.rb file."
|
54
54
|
exit(-1)
|
@@ -56,12 +56,12 @@ class Spiceweasel::RoleList
|
|
56
56
|
#grab any lines with 'recipe[' or 'role['
|
57
57
|
rolerl = File.open("roles/#{role}.rb").grep(/recipe\[|role\[/)
|
58
58
|
rolerl.each do |line|
|
59
|
-
STDOUT.puts "DEBUG: role: '#{role}' line: '#{line}'" if DEBUG
|
59
|
+
STDOUT.puts "DEBUG: role: '#{role}' line: '#{line}'" if Spiceweasel::DEBUG
|
60
60
|
line.strip.split(',').each do |rl|
|
61
61
|
if rl =~ /recipe\[/ #it's a cookbook
|
62
62
|
#split on the brackets and any colons
|
63
63
|
dep = rl.split(/\[|\]/)[1].split(':')[0]
|
64
|
-
STDOUT.puts "DEBUG: role: '#{role}' cookbook: '#{rl}': dep: '#{dep}'" if DEBUG
|
64
|
+
STDOUT.puts "DEBUG: role: '#{role}' cookbook: '#{rl}': dep: '#{dep}'" if Spiceweasel::DEBUG
|
65
65
|
if !cookbooks.member?(dep)
|
66
66
|
STDERR.puts "ERROR: Cookbook dependency '#{dep}' from role '#{role}' is missing from the list of cookbooks in the manifest."
|
67
67
|
exit(-1)
|
@@ -69,7 +69,7 @@ class Spiceweasel::RoleList
|
|
69
69
|
elsif rl =~ /role\[/ #it's a role
|
70
70
|
#split on the brackets
|
71
71
|
dep = rl.split(/\[|\]/)[1]
|
72
|
-
STDOUT.puts "DEBUG: role: '#{role}' role: '#{rl}': dep: '#{dep}'" if DEBUG
|
72
|
+
STDOUT.puts "DEBUG: role: '#{role}' role: '#{rl}': dep: '#{dep}'" if Spiceweasel::DEBUG
|
73
73
|
if !roles.member?(dep)
|
74
74
|
STDERR.puts "ERROR: Role dependency '#{dep}' from role '#{role}' is missing from the list of roles in the manifest."
|
75
75
|
exit(-1)
|
@@ -84,7 +84,7 @@ class Spiceweasel::RoleList
|
|
84
84
|
JSON.create_id = nil
|
85
85
|
rolefile = JSON.parse(f, {:symbolize_names => false})
|
86
86
|
#validate that the name inside the file matches
|
87
|
-
STDOUT.puts "DEBUG: role: '#{role}' name: '#{rolefile['name']}'" if DEBUG
|
87
|
+
STDOUT.puts "DEBUG: role: '#{role}' name: '#{rolefile['name']}'" if Spiceweasel::DEBUG
|
88
88
|
if !role.eql?(rolefile['name'])
|
89
89
|
STDERR.puts "ERROR: Role '#{role}' listed in the manifest does not match the name '#{rolefile['name']}' within the 'roles/#{role}.json' file."
|
90
90
|
exit(-1)
|
@@ -94,7 +94,7 @@ class Spiceweasel::RoleList
|
|
94
94
|
if rl =~ /recipe\[/ #it's a cookbook
|
95
95
|
#split on the brackets and any colons
|
96
96
|
dep = rl.split(/\[|\]/)[1].split(':')[0]
|
97
|
-
STDOUT.puts "DEBUG: role: '#{role}' cookbook: '#{rl}': dep: '#{dep}'" if DEBUG
|
97
|
+
STDOUT.puts "DEBUG: role: '#{role}' cookbook: '#{rl}': dep: '#{dep}'" if Spiceweasel::DEBUG
|
98
98
|
if !cookbooks.member?(dep)
|
99
99
|
STDERR.puts "ERROR: Cookbook dependency '#{dep}' from role '#{role}' is missing from the list of cookbooks in the manifest."
|
100
100
|
exit(-1)
|
@@ -102,7 +102,7 @@ class Spiceweasel::RoleList
|
|
102
102
|
elsif rl =~ /role\[/ #it's a role
|
103
103
|
#split on the brackets
|
104
104
|
dep = rl.split(/\[|\]/)[1]
|
105
|
-
STDOUT.puts "DEBUG: role: '#{role}' role: '#{rl}': dep: '#{dep}'" if DEBUG
|
105
|
+
STDOUT.puts "DEBUG: role: '#{role}' role: '#{rl}': dep: '#{dep}'" if Spiceweasel::DEBUG
|
106
106
|
if !roles.member?(dep)
|
107
107
|
STDERR.puts "ERROR: Role dependency '#{dep}' from role '#{role}' is missing from the list of roles in the manifest."
|
108
108
|
exit(-1)
|
data/lib/spiceweasel/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spiceweasel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-09-06 00:00:00.000000000Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: json
|
17
|
-
requirement: &
|
17
|
+
requirement: &70331172604580 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70331172604580
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: mixlib-cli
|
28
|
-
requirement: &
|
28
|
+
requirement: &70331172604160 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70331172604160
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: rspec
|
39
|
-
requirement: &
|
39
|
+
requirement: &70331172603740 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,7 +44,7 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70331172603740
|
48
48
|
description: Provides a CLI tool for generating knife commands to build Chef-managed
|
49
49
|
infrastructure from a simple YAML or JSON file.
|
50
50
|
email:
|