spiceweasel 1.0.0 → 1.1.0
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.
- data/README.md +45 -15
- data/bin/spiceweasel +37 -19
- data/lib/spiceweasel.rb +2 -0
- data/lib/spiceweasel/cli.rb +21 -4
- data/lib/spiceweasel/cookbook_data.rb +66 -0
- data/lib/spiceweasel/cookbook_list.rb +4 -2
- data/lib/spiceweasel/directory_extractor.rb +140 -0
- data/lib/spiceweasel/environment_list.rb +8 -6
- data/lib/spiceweasel/node_list.rb +1 -1
- data/lib/spiceweasel/role_list.rb +7 -6
- data/lib/spiceweasel/version.rb +2 -2
- metadata +12 -11
data/README.md
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
Description
|
2
2
|
===========
|
3
|
-
Spiceweasel is a command-line tool for batch loading Chef infrastructure from a file
|
3
|
+
Spiceweasel is a command-line tool for batch loading Chef infrastructure from a file. It provides a simple syntax in either JSON or YAML for describing and deploying infrastructure in order with the Chef command-line tool `knife`. This manifest may be bundled with a Chef repository to deploy the infrastructure contained within the repository and validate that the components listed are all present.
|
4
4
|
|
5
5
|
The `examples` directory provides example manifests based on the Quick Starts provided at [http://help.opscode.com/kb/otherhelp](http://help.opscode.com/kb/otherhelp).
|
6
6
|
|
7
|
-
The [https://github.com/mattray/
|
7
|
+
The [https://github.com/mattray/vbacd-repo](https://github.com/mattray/vbacd-repo) provides a working example for bootstrapping a Chef repository with Spiceweasel.
|
8
8
|
|
9
9
|
The [CHANGELOG.md](https://github.com/mattray/spiceweasel/blob/master/CHANGELOG.md) covers current, previous and future development milestones and contains the features backlog.
|
10
10
|
|
11
11
|
Requirements
|
12
12
|
============
|
13
|
-
Spiceweasel currently depends on `knife` to run commands for it, but does not explicitly depend on the `chef` gem. Infrastructure files must either end in .json or .yml to be processed.
|
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 0.10 series.
|
15
|
+
Written and tested initially with Chef 0.9.12 (should still work) and continuing development with the 0.10 series. It is tested with Ruby 1.8.7 and 1.9.2.
|
16
16
|
|
17
17
|
File Syntax
|
18
18
|
===========
|
@@ -26,20 +26,17 @@ From the `example.yml`:
|
|
26
26
|
cookbooks:
|
27
27
|
- apache2:
|
28
28
|
- apt:
|
29
|
-
- 1.
|
29
|
+
- 1.2.0
|
30
30
|
- mysql:
|
31
|
-
|
32
31
|
environments:
|
33
32
|
- development:
|
34
33
|
- qa:
|
35
34
|
- production:
|
36
|
-
|
37
35
|
roles:
|
38
36
|
- base:
|
39
37
|
- iisserver:
|
40
38
|
- monitoring:
|
41
39
|
- webserver:
|
42
|
-
|
43
40
|
data bags:
|
44
41
|
- users:
|
45
42
|
- alice
|
@@ -51,7 +48,6 @@ data bags:
|
|
51
48
|
- secret secret_key
|
52
49
|
- mysql
|
53
50
|
- rabbitmq
|
54
|
-
|
55
51
|
nodes:
|
56
52
|
- serverA:
|
57
53
|
- role[base]
|
@@ -84,7 +80,7 @@ From the `example.json`:
|
|
84
80
|
{"apache2":[]},
|
85
81
|
{"apt":
|
86
82
|
[
|
87
|
-
"1.
|
83
|
+
"1.2.0"
|
88
84
|
]
|
89
85
|
},
|
90
86
|
{"mysql":[]}
|
@@ -174,7 +170,7 @@ The `cookbooks` section of the manifest currently supports `knife cookbook uploa
|
|
174
170
|
cookbooks:
|
175
171
|
- apache2:
|
176
172
|
- apt:
|
177
|
-
- 1.
|
173
|
+
- 1.2.0
|
178
174
|
- mysql:
|
179
175
|
```
|
180
176
|
|
@@ -182,7 +178,7 @@ produces the knife commands
|
|
182
178
|
|
183
179
|
```
|
184
180
|
knife cookbook upload apache2
|
185
|
-
knife cookbook site download apt 1.
|
181
|
+
knife cookbook site download apt 1.2.0 --file cookbooks/apt.tgz
|
186
182
|
tar -C cookbooks/ -xf cookbooks/apt.tgz
|
187
183
|
rm -f cookbooks/apt.tgz
|
188
184
|
knife cookbook upload apt
|
@@ -253,8 +249,8 @@ knife data bag from file users alice.json
|
|
253
249
|
knife data bag from file users bob.json
|
254
250
|
knife data bag from file users chuck.json
|
255
251
|
knife data bag create data
|
256
|
-
knife data bag from file
|
257
|
-
knife data bag from file
|
252
|
+
knife data bag from file data dataA.json
|
253
|
+
knife data bag from file data dataB.json
|
258
254
|
knife data bag create passwords
|
259
255
|
knife data bag from file passwords mysql.json --secret-file secret_key
|
260
256
|
knife data bag from file passwords rabbitmq.json --secret-file secret_key
|
@@ -306,6 +302,25 @@ knife bootstrap windows ssh winboxB -x Administrator -P 'super_secret_password'
|
|
306
302
|
knife bootstrap windows ssh winboxC -x Administrator -P 'super_secret_password' -r 'role[base],role[iisserver]'
|
307
303
|
```
|
308
304
|
|
305
|
+
Extract
|
306
|
+
=======
|
307
|
+
Spiceweasel may also be used to generate knife commands or Spiceweasel manifests in JSON or YAML.
|
308
|
+
|
309
|
+
```
|
310
|
+
spiceweasel --extractlocal
|
311
|
+
```
|
312
|
+
When run in your Chef repository generates the `knife` commands required to upload all the existing infrastructure that is found in the cookbooks, roles, environments and data bags directories with validation.
|
313
|
+
|
314
|
+
```
|
315
|
+
spiceweasel --extractjson
|
316
|
+
```
|
317
|
+
When run in your Chef repository generates JSON-formatted output that may be captured and used as your Spiceweasel manifest file.
|
318
|
+
|
319
|
+
```
|
320
|
+
spiceweasel --extractyaml
|
321
|
+
```
|
322
|
+
When run in your Chef repository generates YAML-formatted output that may be captured and used as your Spiceweasel manifest file.
|
323
|
+
|
309
324
|
Usage
|
310
325
|
=====
|
311
326
|
To parse a spiceweasel manifest, run the following from your Chef repository directory:
|
@@ -322,6 +337,9 @@ spiceweasel path/to/infrastructure.yml
|
|
322
337
|
|
323
338
|
This will generate the knife commands to build the described infrastructure. Infrastructure manifest files must end in either `.json` or `.yml`.
|
324
339
|
|
340
|
+
OPTIONS
|
341
|
+
=======
|
342
|
+
|
325
343
|
-c/--knifeconfig
|
326
344
|
----------------
|
327
345
|
Specify a knife.rb configuration file to use with the knife commands.
|
@@ -338,6 +356,18 @@ The delete command will generate the knife commands to delete the infrastructure
|
|
338
356
|
--------
|
339
357
|
This is the default action, printing the knife commands to be run without executing them.
|
340
358
|
|
359
|
+
--extractlocal
|
360
|
+
--------------
|
361
|
+
When run in a chef repository, this will print the knife commands to be run.
|
362
|
+
|
363
|
+
--extractjson
|
364
|
+
--------------
|
365
|
+
When run in a chef repository, this will print a new JSON manifest that may be used as input to Spiceweasel.
|
366
|
+
|
367
|
+
--extractyaml
|
368
|
+
--------------
|
369
|
+
When run in a chef repository, this will print a new YAML manifest that may be used as input to Spiceweasel.
|
370
|
+
|
341
371
|
-h/--help
|
342
372
|
---------
|
343
373
|
Print the currently-supported usage options for spiceweasel.
|
@@ -366,7 +396,7 @@ License and Author
|
|
366
396
|
==================
|
367
397
|
Author: Matt Ray <matt@opscode.com>
|
368
398
|
|
369
|
-
Copyright: 2011 Opscode, Inc
|
399
|
+
Copyright: 2011-2012 Opscode, Inc
|
370
400
|
|
371
401
|
Licensed under the Apache License, Version 2.0 (the "License");
|
372
402
|
you may not use this file except in compliance with the License.
|
data/bin/spiceweasel
CHANGED
@@ -34,6 +34,9 @@ begin
|
|
34
34
|
PARALLEL = cli.config[:parallel]
|
35
35
|
SITEINSTALL = cli.config[:siteinstall]
|
36
36
|
NOVALIDATION = cli.config[:novalidation]
|
37
|
+
EXTRACTLOCAL = cli.config[:extractlocal]
|
38
|
+
EXTRACTYAML = cli.config[:extractyaml]
|
39
|
+
EXTRACTJSON = cli.config[:extractjson]
|
37
40
|
rescue OptionParser::InvalidOption => e
|
38
41
|
STDERR.puts e.message
|
39
42
|
puts cli.opt_parser.to_s
|
@@ -41,28 +44,37 @@ rescue OptionParser::InvalidOption => e
|
|
41
44
|
end
|
42
45
|
|
43
46
|
if cli.config[:knifeconfig]
|
44
|
-
options['knife_options']
|
47
|
+
options['knife_options'] += " -c " + cli.config[:knifeconfig]
|
45
48
|
end
|
46
49
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
50
|
+
if cli.config[:serverurl]
|
51
|
+
options['knife_options'] += " --server-url " + cli.config[:serverurl]
|
52
|
+
end
|
53
|
+
|
54
|
+
if EXTRACTLOCAL || EXTRACTJSON || EXTRACTYAML
|
55
|
+
input = Spiceweasel::DirectoryExtractor.parse_objects
|
56
|
+
STDOUT.puts "DEBUG: extract input: #{input}" if DEBUG
|
57
|
+
else
|
58
|
+
begin
|
59
|
+
file = ARGV.last
|
60
|
+
STDOUT.puts "DEBUG: file: #{file}" if DEBUG
|
61
|
+
if (file.end_with?(".yml"))
|
62
|
+
input = YAML.load_file ARGV.last
|
63
|
+
elsif (file.end_with?(".json"))
|
64
|
+
input = JSON.parse(File.read(ARGV.last))
|
65
|
+
else
|
66
|
+
STDERR.puts "ERROR: Unknown file type, please use a file ending with either '.json' or '.yml'."
|
67
|
+
exit(-1)
|
68
|
+
end
|
69
|
+
rescue JSON::ParserError => e
|
70
|
+
STDERR.puts e.message
|
71
|
+
STDERR.puts "ERROR: Parsing error in the infrastructure file provided."
|
72
|
+
exit(-1)
|
73
|
+
rescue Exception
|
74
|
+
STDERR.puts "ERROR: No infrastructure .json or .yml file provided."
|
75
|
+
puts cli.opt_parser.to_s
|
56
76
|
exit(-1)
|
57
77
|
end
|
58
|
-
rescue JSON::ParserError => e
|
59
|
-
STDERR.puts e.message
|
60
|
-
STDERR.puts "ERROR: Parsing error in the infrastructure file provided."
|
61
|
-
exit(-1)
|
62
|
-
rescue Exception
|
63
|
-
STDERR.puts "ERROR: No infrastructure .json or .yml file provided."
|
64
|
-
puts cli.opt_parser.to_s
|
65
|
-
exit(-1)
|
66
78
|
end
|
67
79
|
|
68
80
|
create = String.new()
|
@@ -94,7 +106,13 @@ elsif cli.config[:rebuild]
|
|
94
106
|
puts delete unless delete.empty?
|
95
107
|
puts create unless create.empty?
|
96
108
|
else
|
97
|
-
|
109
|
+
if EXTRACTJSON
|
110
|
+
puts JSON.pretty_generate(input)
|
111
|
+
elsif EXTRACTYAML
|
112
|
+
puts input.to_yaml
|
113
|
+
else
|
114
|
+
puts create unless create.empty?
|
115
|
+
end
|
98
116
|
end
|
99
117
|
#else
|
100
118
|
#eventually we will execute instead of printing knife commands
|
data/lib/spiceweasel.rb
CHANGED
@@ -23,4 +23,6 @@ module Spiceweasel
|
|
23
23
|
autoload :RoleList, 'spiceweasel/role_list'
|
24
24
|
autoload :DataBagList, 'spiceweasel/data_bag_list'
|
25
25
|
autoload :NodeList, 'spiceweasel/node_list'
|
26
|
+
autoload :DirectoryExtractor, 'spiceweasel/directory_extractor'
|
27
|
+
autoload :CookbookData, 'spiceweasel/cookbook_data'
|
26
28
|
end
|
data/lib/spiceweasel/cli.rb
CHANGED
@@ -4,7 +4,19 @@ require 'spiceweasel/version'
|
|
4
4
|
class Spiceweasel::CLI
|
5
5
|
include Mixlib::CLI
|
6
6
|
|
7
|
-
banner("Usage: spiceweasel [option] file")
|
7
|
+
banner("Usage: spiceweasel [option] file\n spiceweasel [option] --extractlocal")
|
8
|
+
|
9
|
+
option :extractlocal,
|
10
|
+
:long => "--extractlocal",
|
11
|
+
:description => "Use contents of local chef repository directories to generate knife commands to build infrastructure"
|
12
|
+
|
13
|
+
option :extractjson,
|
14
|
+
:long => "--extractjson",
|
15
|
+
:description => "Use contents of local chef repository directories to generate JSON spiceweasel manifest"
|
16
|
+
|
17
|
+
option :extractyaml,
|
18
|
+
:long => "--extractyaml",
|
19
|
+
:description => "Use contents of local chef repository directories to generate YAML spiceweasel manifest"
|
8
20
|
|
9
21
|
option :debug,
|
10
22
|
:long => "--debug",
|
@@ -14,7 +26,7 @@ class Spiceweasel::CLI
|
|
14
26
|
option :delete,
|
15
27
|
:short => "-d",
|
16
28
|
:long => "--delete",
|
17
|
-
:description => "Print the knife commands to
|
29
|
+
:description => "Print the knife commands to delete the infrastructure",
|
18
30
|
:boolean => true
|
19
31
|
|
20
32
|
option :dryrun,
|
@@ -31,10 +43,15 @@ class Spiceweasel::CLI
|
|
31
43
|
:show_options => true,
|
32
44
|
:exit => 0
|
33
45
|
|
46
|
+
option :serverurl,
|
47
|
+
:short => "-s URL",
|
48
|
+
:long => "--server-url URL",
|
49
|
+
:description => "Specify the Chef Server URL"
|
50
|
+
|
34
51
|
option :knifeconfig,
|
35
52
|
:short => "-c CONFIG",
|
36
53
|
:long => "--knifeconfig CONFIG",
|
37
|
-
:description => "Specify the knife.rb configuration file
|
54
|
+
:description => "Specify the knife.rb configuration file"
|
38
55
|
|
39
56
|
option :novalidation,
|
40
57
|
:long => "--novalidation",
|
@@ -60,7 +77,7 @@ class Spiceweasel::CLI
|
|
60
77
|
option :version,
|
61
78
|
:short => "-v",
|
62
79
|
:long => "--version",
|
63
|
-
:description => "
|
80
|
+
:description => "Show spiceweasel version",
|
64
81
|
:boolean => true,
|
65
82
|
:proc => lambda {|v| puts "Spiceweasel: #{Spiceweasel::VERSION}" },
|
66
83
|
:exit => 0
|
@@ -0,0 +1,66 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Geoff Meakin
|
3
|
+
# Author:: Matt Ray (<matt@opscode.com>)
|
4
|
+
#
|
5
|
+
# Copyright:: 2012, Opscode, Inc <legal@opscode.com>
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
class Spiceweasel::CookbookData
|
21
|
+
|
22
|
+
attr_accessor :_name, :_dependencies, :_version
|
23
|
+
|
24
|
+
def initialize(file_name)
|
25
|
+
@_name = file_name.split('/').last
|
26
|
+
@_dependencies = []
|
27
|
+
@_version = ""
|
28
|
+
@file_name = file_name
|
29
|
+
end
|
30
|
+
|
31
|
+
def is_readable?
|
32
|
+
return false unless File.directory?("cookbooks/#{@_name}")
|
33
|
+
return false unless File.exists?("cookbooks/#{@_name}/metadata.rb")
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def read
|
38
|
+
if File.exists?("cookbooks/#{@_name}/metadata.rb") && File.readable?("cookbooks/#{@_name}/metadata.rb")
|
39
|
+
self.instance_eval(IO.read("cookbooks/#{@_name}/metadata.rb"), "cookbooks/#{@_name}/metadata.rb", 1)
|
40
|
+
else
|
41
|
+
raise IOError, "Cannot open or read cookbooks/#{@_name}/metadata.rb!"
|
42
|
+
end
|
43
|
+
{:name => @_name, :version => @_version, :dependencies => @_dependencies }
|
44
|
+
end
|
45
|
+
|
46
|
+
def name(*args) # Override metadata.rb DSL
|
47
|
+
@_name = args.shift
|
48
|
+
end
|
49
|
+
|
50
|
+
def version(*args) # Override metadata.rb DSL
|
51
|
+
@_version = args.shift
|
52
|
+
end
|
53
|
+
|
54
|
+
def depends(*args) # Override metadata.rb DSL
|
55
|
+
cookbook = args.shift
|
56
|
+
if args.length > 0
|
57
|
+
cookbook_version = args.shift
|
58
|
+
end
|
59
|
+
@_dependencies << {:cookbook => cookbook, :version => cookbook_version}
|
60
|
+
end
|
61
|
+
|
62
|
+
def method_missing(m, *args, &block)
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -65,13 +65,14 @@ class Spiceweasel::CookbookList
|
|
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
69
|
line = dependency.split()
|
69
70
|
cbdep = ''
|
70
|
-
if line[1]
|
71
|
+
if line[1] =~ /^"/ #ignore variables and versions
|
71
72
|
cbdep = line[1].gsub(/"/,'')
|
72
73
|
cbdep.gsub!(/\,/,'') if cbdep.end_with?(',')
|
73
74
|
end
|
74
|
-
STDOUT.puts "DEBUG: #{cookbook} metadata depends: #{cbdep}" if DEBUG
|
75
|
+
STDOUT.puts "DEBUG: cookbook #{cookbook} metadata depends: #{cbdep}" if DEBUG
|
75
76
|
@dependencies << cbdep
|
76
77
|
end
|
77
78
|
return @cookbook
|
@@ -79,6 +80,7 @@ class Spiceweasel::CookbookList
|
|
79
80
|
|
80
81
|
#compare the list of cookbook deps with those specified
|
81
82
|
def validateDependencies()
|
83
|
+
STDOUT.puts "DEBUG: cookbook validateDependencies: '#{@dependencies}'" if DEBUG
|
82
84
|
@dependencies.each do |dep|
|
83
85
|
if !member?(dep)
|
84
86
|
STDERR.puts "ERROR: Cookbook dependency '#{dep}' is missing from the list of cookbooks in the manifest."
|
@@ -0,0 +1,140 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Geoff Meakin
|
3
|
+
# Author:: Matt Ray (<matt@opscode.com>)
|
4
|
+
#
|
5
|
+
# Copyright:: 2012, Opscode, Inc <legal@opscode.com>
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
class Spiceweasel::DirectoryExtractor
|
21
|
+
|
22
|
+
def self.parse_objects
|
23
|
+
objects = {"cookbooks" => nil, "roles" => nil, "environments" => nil, "data bags" => nil, "nodes" => nil}
|
24
|
+
# COOKBOOKS
|
25
|
+
cookbooks = []
|
26
|
+
Dir.glob("cookbooks/*").each do |cookbook_full_path|
|
27
|
+
cookbook = self.grab_filename_from_path cookbook_full_path
|
28
|
+
STDOUT.puts "DEBUG: dir_ext: cookbook: '#{cookbook}'" if DEBUG
|
29
|
+
cookbook_data = Spiceweasel::CookbookData.new(cookbook)
|
30
|
+
if cookbook_data.is_readable?
|
31
|
+
cookbooks << cookbook_data.read
|
32
|
+
end
|
33
|
+
end
|
34
|
+
cookbook_names = self.order_cookbooks_by_dependency cookbooks
|
35
|
+
objects["cookbooks"] = cookbook_names unless cookbook_names.empty?
|
36
|
+
|
37
|
+
# ROLES
|
38
|
+
roles = []
|
39
|
+
Dir.glob("roles/*.{rb,json}").each do |role_full_path|
|
40
|
+
role = self.grab_name_from_path role_full_path
|
41
|
+
STDOUT.puts "DEBUG: dir_ext: role: '#{role}'" if DEBUG
|
42
|
+
roles << {role => nil}
|
43
|
+
end
|
44
|
+
objects["roles"] = roles unless roles.nil?
|
45
|
+
# ENVIRONMENTS
|
46
|
+
environments = []
|
47
|
+
Dir.glob("environments/*.{rb,json}").each do |environment_full_path|
|
48
|
+
environment = self.grab_name_from_path environment_full_path
|
49
|
+
STDOUT.puts "DEBUG: dir_ext: environment: '#{environment}'" if DEBUG
|
50
|
+
environments << {environment => nil}
|
51
|
+
end
|
52
|
+
objects["environments"] = environments unless environments.empty?
|
53
|
+
# DATA BAGS
|
54
|
+
data_bags = []
|
55
|
+
Dir.glob("data_bags/*").each do |data_bag_full_path|
|
56
|
+
data_bag = data_bag_full_path.split('/').last
|
57
|
+
STDOUT.puts "DEBUG: dir_ext: data_bag: '#{data_bag}'" if DEBUG
|
58
|
+
data_bag_items = []
|
59
|
+
Dir.glob("#{data_bag_full_path}/*.{rb,json}").each do |data_bag_item_full_path|
|
60
|
+
STDOUT.puts "DEBUG: dir_ext: data_bag: '#{data_bag}':'#{data_bag_item_full_path}'" if DEBUG
|
61
|
+
data_bag_items << self.grab_name_from_path(data_bag_item_full_path)
|
62
|
+
end if File.directory?(data_bag_full_path)
|
63
|
+
data_bags << {data_bag => data_bag_items} unless data_bag_items.empty?
|
64
|
+
end
|
65
|
+
objects["data bags"] = data_bags unless data_bags.empty?
|
66
|
+
# NODES
|
67
|
+
# TODO: Cant use this yet as node_list.rb doesnt support node from file syntax but expects the node info to be part of the objects passed in
|
68
|
+
# nodes = []
|
69
|
+
# Dir.glob("nodes/*.{rb,json}").each do |node_full_path|
|
70
|
+
# node = self.grab_name_from_path node_full_path
|
71
|
+
# nodes << {node => nil}
|
72
|
+
# end
|
73
|
+
# objects["nodes"] = nodes unless nodes.empty?
|
74
|
+
|
75
|
+
objects
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.grab_filename_from_path path
|
79
|
+
path.split('/').last
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.grab_name_from_path path
|
83
|
+
name = self.grab_filename_from_path(path).split('.')
|
84
|
+
if name.length>1
|
85
|
+
name.pop
|
86
|
+
end
|
87
|
+
name.join('.')
|
88
|
+
end
|
89
|
+
def self.order_cookbooks_by_dependency cookbooks
|
90
|
+
|
91
|
+
# Weak algorithm, not particularly elegant, ignores version info as unlikely to have two versions of a cookbook anyway
|
92
|
+
ordered_cookbooks = []
|
93
|
+
|
94
|
+
left_to_sort = cookbooks
|
95
|
+
num_sorted_cookbooks_this_iteration = -1
|
96
|
+
|
97
|
+
while left_to_sort.size > 0 && num_sorted_cookbooks_this_iteration != 0
|
98
|
+
|
99
|
+
unsorted_cookbooks = left_to_sort
|
100
|
+
left_to_sort = []
|
101
|
+
num_sorted_cookbooks_this_iteration
|
102
|
+
unsorted_cookbooks.each do |cookbook|
|
103
|
+
name = cookbook[:name]
|
104
|
+
dependencies = cookbook[:dependencies]
|
105
|
+
|
106
|
+
next if ordered_cookbooks.include? name
|
107
|
+
|
108
|
+
if dependencies.nil?
|
109
|
+
ordered_cookbooks << name
|
110
|
+
num_sorted_cookbooks_this_iteration += 1
|
111
|
+
next
|
112
|
+
end
|
113
|
+
|
114
|
+
dependencies_satisfied_yet = true
|
115
|
+
dependencies.each {|dependency| dependencies_satisfied_yet = false unless ordered_cookbooks.include? dependency[:cookbook]}
|
116
|
+
if dependencies_satisfied_yet
|
117
|
+
ordered_cookbooks << name
|
118
|
+
num_sorted_cookbooks_this_iteration += 1
|
119
|
+
next
|
120
|
+
end
|
121
|
+
|
122
|
+
left_to_sort << cookbook
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
if left_to_sort.size > 0
|
129
|
+
STDERR.puts "ERROR: Dependencies not satisfied or circular dependencies between cookbooks: #{left_to_sort}"
|
130
|
+
exit(-1)
|
131
|
+
end
|
132
|
+
output_cookbooks = []
|
133
|
+
ordered_cookbooks.each do |cookbook|
|
134
|
+
output_cookbooks << {cookbook => nil}
|
135
|
+
end
|
136
|
+
output_cookbooks
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
@@ -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.
|
@@ -65,15 +65,17 @@ class Spiceweasel::EnvironmentList
|
|
65
65
|
elsif File.exists?("environments/#{environment}.json")
|
66
66
|
#load the json, don't symbolize since we don't need json_class
|
67
67
|
f = File.read("environments/#{environment}.json")
|
68
|
-
|
68
|
+
JSON.create_id = nil
|
69
|
+
envfile = JSON.parse(f, {:symbolize_names => false})
|
70
|
+
STDOUT.puts "DEBUG: environment: '#{environment}' file: '#{envfile}'" if DEBUG
|
69
71
|
#validate that the name inside the file matches
|
70
|
-
STDOUT.puts "DEBUG: environment: '#{environment}' name: '#{envfile[
|
71
|
-
if !environment.eql?(envfile[
|
72
|
-
STDERR.puts "ERROR: Environment '#{environment}' listed in the manifest does not match the name '#{envfile[
|
72
|
+
STDOUT.puts "DEBUG: environment: '#{environment}' name: '#{envfile['name']}'" if DEBUG
|
73
|
+
if !environment.eql?(envfile['name'])
|
74
|
+
STDERR.puts "ERROR: Environment '#{environment}' listed in the manifest does not match the name '#{envfile['name']}' within the 'environments/#{environment}.json' file."
|
73
75
|
exit(-1)
|
74
76
|
end
|
75
77
|
#validate the cookbooks exist if they're mentioned
|
76
|
-
envfile[
|
78
|
+
envfile['cookbook_versions'].keys.each do |cb|
|
77
79
|
STDOUT.puts "DEBUG: environment: '#{environment}' cookbook: '#{cb}'" if DEBUG
|
78
80
|
if !cookbooks.member?(cb.to_s)
|
79
81
|
STDERR.puts "ERROR: Cookbook dependency '#{cb}' from environment '#{environment}' is missing from the list of cookbooks in the manifest."
|
@@ -13,7 +13,7 @@ class Spiceweasel::NodeList
|
|
13
13
|
STDOUT.puts "DEBUG: node: 'node[nname]' options: '#{noptions}'" if DEBUG
|
14
14
|
validateOptions(nname, noptions, environments) unless NOVALIDATION
|
15
15
|
#provider support
|
16
|
-
if nname.start_with?("bluebox ","clodo ","cs ","ec2 ","gandi ","openstack ","rackspace ","slicehost ","terremark ","voxel ")
|
16
|
+
if nname.start_with?("bluebox ","clodo ","cs ","ec2 ","gandi ","hp ","openstack ","rackspace ","slicehost ","terremark ","voxel ")
|
17
17
|
provider = nname.split()
|
18
18
|
count = 1
|
19
19
|
if (provider.length == 2)
|
@@ -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.
|
@@ -81,15 +81,16 @@ class Spiceweasel::RoleList
|
|
81
81
|
elsif File.exists?("roles/#{role}.json")
|
82
82
|
#load the json, don't symbolize since we don't need json_class
|
83
83
|
f = File.read("roles/#{role}.json")
|
84
|
-
|
84
|
+
JSON.create_id = nil
|
85
|
+
rolefile = JSON.parse(f, {:symbolize_names => false})
|
85
86
|
#validate that the name inside the file matches
|
86
|
-
STDOUT.puts "DEBUG: role: '#{role}' name: '#{rolefile[
|
87
|
-
if !role.eql?(rolefile[
|
88
|
-
STDERR.puts "ERROR: Role '#{role}' listed in the manifest does not match the name '#{rolefile[
|
87
|
+
STDOUT.puts "DEBUG: role: '#{role}' name: '#{rolefile['name']}'" if DEBUG
|
88
|
+
if !role.eql?(rolefile['name'])
|
89
|
+
STDERR.puts "ERROR: Role '#{role}' listed in the manifest does not match the name '#{rolefile['name']}' within the 'roles/#{role}.json' file."
|
89
90
|
exit(-1)
|
90
91
|
end
|
91
92
|
#validate the cookbooks and roles exist if they're mentioned in run_lists
|
92
|
-
rolefile[
|
93
|
+
rolefile['run_list'].each do |rl|
|
93
94
|
if rl =~ /recipe\[/ #it's a cookbook
|
94
95
|
#split on the brackets and any colons
|
95
96
|
dep = rl.split(/\[|\]/)[1].split(':')[0]
|
data/lib/spiceweasel/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Matt Ray (<matt@opscode.com>)
|
3
3
|
#
|
4
|
-
# Copyright:: 2011
|
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.
|
@@ -17,5 +17,5 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
module Spiceweasel
|
20
|
-
VERSION = "1.
|
20
|
+
VERSION = "1.1.0"
|
21
21
|
end
|
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.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,12 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
14
|
-
default_executable:
|
13
|
+
date: 2012-05-22 00:00:00.000000000Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: json
|
18
|
-
requirement: &
|
17
|
+
requirement: &70140549239420 !ruby/object:Gem::Requirement
|
19
18
|
none: false
|
20
19
|
requirements:
|
21
20
|
- - ! '>='
|
@@ -23,10 +22,10 @@ dependencies:
|
|
23
22
|
version: '0'
|
24
23
|
type: :runtime
|
25
24
|
prerelease: false
|
26
|
-
version_requirements: *
|
25
|
+
version_requirements: *70140549239420
|
27
26
|
- !ruby/object:Gem::Dependency
|
28
27
|
name: mixlib-cli
|
29
|
-
requirement: &
|
28
|
+
requirement: &70140549239000 !ruby/object:Gem::Requirement
|
30
29
|
none: false
|
31
30
|
requirements:
|
32
31
|
- - ! '>='
|
@@ -34,10 +33,10 @@ dependencies:
|
|
34
33
|
version: '0'
|
35
34
|
type: :runtime
|
36
35
|
prerelease: false
|
37
|
-
version_requirements: *
|
36
|
+
version_requirements: *70140549239000
|
38
37
|
- !ruby/object:Gem::Dependency
|
39
38
|
name: rspec
|
40
|
-
requirement: &
|
39
|
+
requirement: &70140549238580 !ruby/object:Gem::Requirement
|
41
40
|
none: false
|
42
41
|
requirements:
|
43
42
|
- - ! '>='
|
@@ -45,7 +44,7 @@ dependencies:
|
|
45
44
|
version: '0'
|
46
45
|
type: :development
|
47
46
|
prerelease: false
|
48
|
-
version_requirements: *
|
47
|
+
version_requirements: *70140549238580
|
49
48
|
description: Provides a CLI tool for generating knife commands to build Chef-managed
|
50
49
|
infrastructure from a simple YAML or JSON file.
|
51
50
|
email:
|
@@ -58,8 +57,10 @@ extra_rdoc_files: []
|
|
58
57
|
files:
|
59
58
|
- bin/spiceweasel
|
60
59
|
- lib/spiceweasel/cli.rb
|
60
|
+
- lib/spiceweasel/cookbook_data.rb
|
61
61
|
- lib/spiceweasel/cookbook_list.rb
|
62
62
|
- lib/spiceweasel/data_bag_list.rb
|
63
|
+
- lib/spiceweasel/directory_extractor.rb
|
63
64
|
- lib/spiceweasel/environment_list.rb
|
64
65
|
- lib/spiceweasel/node_list.rb
|
65
66
|
- lib/spiceweasel/role_list.rb
|
@@ -67,7 +68,6 @@ files:
|
|
67
68
|
- lib/spiceweasel.rb
|
68
69
|
- README.md
|
69
70
|
- spec/bin/spiceweasel_spec.rb
|
70
|
-
has_rdoc: true
|
71
71
|
homepage: http://github.com/mattray/spiceweasel
|
72
72
|
licenses: []
|
73
73
|
post_install_message:
|
@@ -88,9 +88,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
88
|
version: '0'
|
89
89
|
requirements: []
|
90
90
|
rubyforge_project: spiceweasel
|
91
|
-
rubygems_version: 1.
|
91
|
+
rubygems_version: 1.8.15
|
92
92
|
signing_key:
|
93
93
|
specification_version: 3
|
94
94
|
summary: CLI for generating Chef knife commands from a simple YAML file.
|
95
95
|
test_files:
|
96
96
|
- spec/bin/spiceweasel_spec.rb
|
97
|
+
has_rdoc:
|