spiceweasel 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|