spiceweasel 2.1.2 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +26 -25
- data/lib/spiceweasel/cli.rb +53 -24
- data/lib/spiceweasel/clusters.rb +12 -6
- data/lib/spiceweasel/cookbooks.rb +5 -4
- data/lib/spiceweasel/data_bags.rb +17 -8
- data/lib/spiceweasel/environments.rb +22 -10
- data/lib/spiceweasel/extract_local.rb +1 -1
- data/lib/spiceweasel/roles.rb +14 -2
- data/lib/spiceweasel/version.rb +1 -1
- data/spec/bin/spiceweasel_spec.rb +5 -6
- metadata +2 -2
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
# Description #
|
5
5
|
|
6
|
-
Spiceweasel is a command-line tool for batch loading Chef infrastructure
|
6
|
+
Spiceweasel is a command-line tool for batch loading Chef infrastructure. It provides a simple syntax in Ruby, 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. The manifest may also be extracted from an existing repository.
|
7
7
|
|
8
8
|
The `examples` directory provides example manifests based on the Quick Starts provided at http://help.opscode.com/kb/otherhelp. The https://github.com/mattray/vbacd-repo provides a working example for bootstrapping a Chef repository with Spiceweasel.
|
9
9
|
|
@@ -11,9 +11,9 @@ The [CHANGELOG.md](https://github.com/mattray/spiceweasel/blob/master/CHANGELOG.
|
|
11
11
|
|
12
12
|
# Requirements #
|
13
13
|
|
14
|
-
Spiceweasel currently depends on `knife` to run commands for it, and requires the `chef` gem for validating cookbook metadata. Infrastructure files must end in `.rb`, `.json` or `.yml` to be processed.
|
14
|
+
Spiceweasel currently depends on `knife` to run commands for it, and requires the `chef` gem for validating cookbook metadata. [Berkshelf](https://berkshelf.com) is a dependency for the Cookbook `Berksfile` support. Infrastructure files must end in `.rb`, `.json` or `.yml` to be processed.
|
15
15
|
|
16
|
-
Written and tested
|
16
|
+
Written and tested with the Chef 11.x series (previous versions of Chef may still work). It is tested with Ruby 1.9.3. Version 2.0 was the last version known to work with Ruby 1.8.7 due to the introduction of the Berkshelf dependency in 2.1.
|
17
17
|
|
18
18
|
# File Syntax #
|
19
19
|
|
@@ -66,10 +66,10 @@ knife cookbook upload mysql ntp
|
|
66
66
|
|
67
67
|
## Berkshelf ##
|
68
68
|
|
69
|
-
If you prefer to use Berkshelf for managing your cookbooks, Spiceweasel supports adding `berksfile:` and the ability to specify the path and any Berkshelf options. You may mix use of `
|
69
|
+
If you prefer to use Berkshelf for managing your cookbooks, Spiceweasel supports adding `berksfile:` and the ability to specify the path and any Berkshelf options. You may mix use of `berksfile:` with `cookbooks:` if you wish as well. Berkshelf-managed cookbooks will be included in the validation of roles, environments and run lists as well. You may simply use the YAML snippet
|
70
70
|
|
71
71
|
``` yaml
|
72
|
-
|
72
|
+
berksfile:
|
73
73
|
```
|
74
74
|
|
75
75
|
which produces the command
|
@@ -94,16 +94,16 @@ berks upload --skip_syntax_check --config some_config.json -b /Users/mray/ws/lab
|
|
94
94
|
|
95
95
|
## Environments ##
|
96
96
|
|
97
|
-
The `environments` section of the manifest currently supports `knife environment from file FOO` where `FOO` is the name of the environment file ending in `.rb` or `.json` in the `environments` directory. Validation is done to ensure the filename matches the environment and that any cookbooks referenced are listed in the manifest. The example YAML snippet
|
97
|
+
The `environments` section of the manifest currently supports `knife environment from file FOO` where `FOO` is the name of the environment file ending in `.rb` or `.json` in the `environments` directory. You may also pass a wildcard as an entry to load all matching environments (ie. `"*"` or `prod*"`). Validation is done to ensure the filename matches the environment and that any cookbooks referenced are listed in the manifest. The example YAML snippet
|
98
98
|
|
99
99
|
``` yaml
|
100
100
|
environments:
|
101
101
|
- development:
|
102
102
|
- qa:
|
103
|
-
-
|
103
|
+
- "prod*":
|
104
104
|
```
|
105
105
|
|
106
|
-
produces the knife commands
|
106
|
+
assuming the `production` environment exists, produces the knife commands
|
107
107
|
|
108
108
|
```
|
109
109
|
knife environment from file development.rb qa.rb production.rb
|
@@ -111,25 +111,26 @@ knife environment from file development.rb qa.rb production.rb
|
|
111
111
|
|
112
112
|
## Roles ##
|
113
113
|
|
114
|
-
The `roles` section of the manifest currently supports `knife role from file FOO` where `FOO` is the name of the role file ending in `.rb` or `.json` in the `roles` directory. Validation is done to ensure the filename matches the role name and that any cookbooks or roles referenced are listed in the manifest. The example YAML snippet
|
114
|
+
The `roles` section of the manifest currently supports `knife role from file FOO` where `FOO` is the name of the role file ending in `.rb` or `.json` in the `roles` directory. You may also pass a wildcard as an entry to load all matching roles (ie. `"*"` or `data*"`). Validation is done to ensure the filename matches the role name and that any cookbooks or roles referenced are listed in the manifest. The example YAML snippet
|
115
115
|
|
116
116
|
``` yaml
|
117
117
|
roles:
|
118
118
|
- base:
|
119
|
+
- "data*":
|
119
120
|
- iisserver:
|
120
121
|
- monitoring:
|
121
122
|
- webserver:
|
122
123
|
```
|
123
124
|
|
124
|
-
produces the knife commands
|
125
|
+
assuming the `database1.json` and `database2.json` roles exist, this produces the knife commands
|
125
126
|
|
126
127
|
```
|
127
|
-
knife role from file base.rb iisserver.rb monitoring.rb webserver.rb
|
128
|
+
knife role from file base.rb database1.json database2.json iisserver.rb monitoring.rb webserver.rb
|
128
129
|
```
|
129
130
|
|
130
|
-
|
131
|
+
## Data Bags ##
|
131
132
|
|
132
|
-
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 using the `secret: secret_key_filename` attribute. Validation is done to ensure the JSON is properly formatted, the id matches and any secret key files are in the correct locations. Assuming the presence of `dataA.json` and `dataB.json` in the `data_bags/data` directory, the YAML snippet
|
133
|
+
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. `"*"` or `"data*"`). Encrypted data bags are supported by using the `secret: secret_key_filename` attribute. Validation is done to ensure the JSON is properly formatted, the id matches and any secret key files are in the correct locations. Assuming the presence of `dataA.json` and `dataB.json` in the `data_bags/data` directory, the YAML snippet
|
133
134
|
|
134
135
|
``` yaml
|
135
136
|
data bags:
|
@@ -154,7 +155,7 @@ produces the knife commands
|
|
154
155
|
knife data bag create users
|
155
156
|
knife data bag from file users alice.json bob.json chuck.json
|
156
157
|
knife data bag create data
|
157
|
-
knife data bag from file data
|
158
|
+
knife data bag from file data dataA.json dataB.json
|
158
159
|
knife data bag create passwords
|
159
160
|
knife data bag from file passwords mysql.json rabbitmq.json --secret-file secret_key_filename
|
160
161
|
```
|
@@ -205,7 +206,7 @@ nodes:
|
|
205
206
|
- -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -N webserver{{n}}
|
206
207
|
```
|
207
208
|
|
208
|
-
produces the following
|
209
|
+
produces the following
|
209
210
|
|
210
211
|
```
|
211
212
|
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]'"
|
@@ -215,7 +216,7 @@ which generates nodes named "webserver1", "webserver2" and "webserver3".
|
|
215
216
|
|
216
217
|
## Clusters ##
|
217
218
|
|
218
|
-
Clusters are not a type supported by Chef, this is a logical construct added by Spiceweasel to enable managing sets of infrastructure together. The `clusters` section is a special case of `nodes`, where each member of the named cluster in the manifest will be
|
219
|
+
Clusters are not a type supported by Chef, this is a logical construct added by Spiceweasel to enable managing sets of infrastructure together. The `clusters` section is a special case of `nodes`, where each member of the named cluster in the manifest will be put in the same environment to ensure that the entire cluster may be created in sync (refresh and delete coming soon). The node syntax is the same as that under `nodes`, the only addition is the cluster name.
|
219
220
|
|
220
221
|
```
|
221
222
|
clusters:
|
@@ -231,17 +232,17 @@ clusters:
|
|
231
232
|
produces the knife commands
|
232
233
|
|
233
234
|
```
|
234
|
-
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-8af0f326 -f m1.medium -
|
235
|
-
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -
|
236
|
-
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -
|
237
|
-
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -
|
235
|
+
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-8af0f326 -f m1.medium -E amazon
|
236
|
+
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -E amazon -r 'role[webserver],recipe[mysql::client]'
|
237
|
+
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -E amazon -r 'role[webserver],recipe[mysql::client]'
|
238
|
+
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -E amazon -r 'role[webserver],recipe[mysql::client]'
|
238
239
|
```
|
239
240
|
|
240
241
|
Another use of `clusters` is with the `--cluster-file` option, which will allow the use of a different file to define the members of the cluster. If there are any `nodes` or `clusters` defined in the primary manifest file, they will be removed and the content of the `--cluster-file` will be used instead. This allows you to switch the target destination of infrastructure by picking different `--cluster-file` endpoints.
|
241
242
|
|
242
243
|
# Extract #
|
243
244
|
|
244
|
-
Spiceweasel may
|
245
|
+
Spiceweasel may be used to generate knife commands or Spiceweasel manifests in JSON or YAML from an existing Chef repository.
|
245
246
|
|
246
247
|
```
|
247
248
|
spiceweasel --extractlocal
|
@@ -263,13 +264,13 @@ When run in your Chef repository generates YAML-formatted output that may be cap
|
|
263
264
|
To parse a Spiceweasel manifest, run the following from your Chef repository directory:
|
264
265
|
|
265
266
|
```
|
266
|
-
spiceweasel path/to/infrastructure.
|
267
|
+
spiceweasel path/to/infrastructure.yml
|
267
268
|
```
|
268
269
|
|
269
|
-
or
|
270
|
+
or to extract infrastructure
|
270
271
|
|
271
272
|
```
|
272
|
-
spiceweasel
|
273
|
+
spiceweasel --extractlocal
|
273
274
|
```
|
274
275
|
|
275
276
|
This will generate the knife commands to build the described infrastructure. Infrastructure manifest files must end in either `.json` or `.yml`.
|
@@ -336,7 +337,7 @@ Print the version of spiceweasel currently installed.
|
|
336
337
|
|
337
338
|
Author: Matt Ray <matt@opscode.com>
|
338
339
|
|
339
|
-
Copyright: 2011-
|
340
|
+
Copyright: 2011-2013 Opscode, Inc
|
340
341
|
|
341
342
|
Licensed under the Apache License, Version 2.0 (the "License");
|
342
343
|
you may not use this file except in compliance with the License.
|
data/lib/spiceweasel/cli.rb
CHANGED
@@ -88,7 +88,7 @@ module Spiceweasel
|
|
88
88
|
|
89
89
|
option :log_level,
|
90
90
|
:short => "-l LEVEL",
|
91
|
-
:long => "--
|
91
|
+
:long => "--loglevel LEVEL",
|
92
92
|
:description => "Set the log level (debug, info, warn, error, fatal)",
|
93
93
|
:proc => lambda { |l| l.to_sym }
|
94
94
|
|
@@ -132,6 +132,16 @@ module Spiceweasel
|
|
132
132
|
:proc => lambda { |v| puts "Spiceweasel: #{::Spiceweasel::VERSION}" },
|
133
133
|
:exit => 0
|
134
134
|
|
135
|
+
option :cookbook_directory,
|
136
|
+
:short => '-C COOKBOOK_DIR',
|
137
|
+
:long => '--cookbook-dir COOKBOOK_DIR',
|
138
|
+
:description => 'Set cookbook directory. Specify multiple times for multiple directories.',
|
139
|
+
:proc => lambda { |v|
|
140
|
+
Spiceweasel::Config[:cookbook_dir] ||= []
|
141
|
+
Spiceweasel::Config[:cookbook_dir] << v
|
142
|
+
Spiceweasel::Config[:cookbook_dir].uniq!
|
143
|
+
}
|
144
|
+
|
135
145
|
option :unique_id,
|
136
146
|
:long => '--unique-id UID',
|
137
147
|
:description => 'Unique ID generally used for ruby based configs'
|
@@ -149,24 +159,7 @@ module Spiceweasel
|
|
149
159
|
end
|
150
160
|
Spiceweasel::Log.debug("file manifest: #{manifest}")
|
151
161
|
|
152
|
-
|
153
|
-
if berksfile
|
154
|
-
cookbooks = Cookbooks.new(manifest['cookbooks'], berksfile.cookbook_list)
|
155
|
-
create = berksfile.create + cookbooks.create
|
156
|
-
delete = berksfile.delete + cookbooks.delete
|
157
|
-
else
|
158
|
-
cookbooks = Cookbooks.new(manifest['cookbooks'])
|
159
|
-
create = cookbooks.create
|
160
|
-
delete = cookbooks.delete
|
161
|
-
end
|
162
|
-
environments = Environments.new(manifest['environments'], cookbooks)
|
163
|
-
roles = Roles.new(manifest['roles'], environments, cookbooks)
|
164
|
-
data_bags = DataBags.new(manifest['data bags'])
|
165
|
-
nodes = Nodes.new(manifest['nodes'], cookbooks, environments, roles)
|
166
|
-
clusters = Clusters.new(manifest['clusters'], cookbooks, environments, roles)
|
167
|
-
|
168
|
-
create += environments.create + roles.create + data_bags.create + nodes.create + clusters.create
|
169
|
-
delete += environments.delete + roles.delete + data_bags.delete + nodes.delete + clusters.delete
|
162
|
+
create, delete = process_manifest(manifest)
|
170
163
|
|
171
164
|
if Spiceweasel::Config[:extractjson]
|
172
165
|
puts JSON.pretty_generate(manifest)
|
@@ -208,12 +201,23 @@ module Spiceweasel
|
|
208
201
|
ARGV << "-h" if ARGV.empty?
|
209
202
|
begin
|
210
203
|
parse_options
|
204
|
+
# Load knife configuration if using knife config
|
205
|
+
require 'chef/knife'
|
206
|
+
knife = Chef::Knife.new
|
207
|
+
# Only log on error during startup
|
208
|
+
Chef::Config[:verbosity] = 0
|
209
|
+
Chef::Config[:log_level] = :error
|
211
210
|
if @config[:knifeconfig]
|
211
|
+
knife.read_config_file(@config[:knifeconfig])
|
212
212
|
Spiceweasel::Config[:knife_options] = " -c #{@config[:knifeconfig]} "
|
213
|
+
else
|
214
|
+
knife.configure_chef
|
213
215
|
end
|
214
216
|
if @config[:serverurl]
|
215
217
|
Spiceweasel::Config[:knife_options] += "--server-url #{@config[:serverurl]} "
|
216
218
|
end
|
219
|
+
# NOTE: Only set cookbook path via config if path unset
|
220
|
+
Spiceweasel::Config[:cookbook_dir] ||= Chef::Config[:cookbook_path]
|
217
221
|
rescue OptionParser::InvalidOption => e
|
218
222
|
STDERR.puts e.message
|
219
223
|
puts opt_parser.to_s
|
@@ -222,9 +226,11 @@ module Spiceweasel
|
|
222
226
|
end
|
223
227
|
|
224
228
|
def configure_logging
|
225
|
-
Spiceweasel::Log
|
226
|
-
|
227
|
-
|
229
|
+
[Spiceweasel::Log, Chef::Log].each do |log_klass|
|
230
|
+
log_klass.init(Spiceweasel::Config[:log_location])
|
231
|
+
log_klass.level = Spiceweasel::Config[:log_level]
|
232
|
+
log_klass.level = :debug if Spiceweasel::Config[:debug]
|
233
|
+
end
|
228
234
|
end
|
229
235
|
|
230
236
|
def parse_and_validate_input(file)
|
@@ -255,12 +261,35 @@ module Spiceweasel
|
|
255
261
|
exit(-1)
|
256
262
|
rescue Exception => e
|
257
263
|
STDERR.puts "ERROR: Invalid or missing manifest .json, .rb, or .yml file provided."
|
258
|
-
|
259
|
-
|
264
|
+
if(Spiceweasel::Config[:log_level].to_s == 'debug')
|
265
|
+
STDERR.puts "ERROR: #{e}\n#{e.backtrace.join("\n")}"
|
266
|
+
end
|
260
267
|
exit(-1)
|
261
268
|
end
|
262
269
|
output
|
263
270
|
end
|
264
271
|
|
272
|
+
def process_manifest(manifest)
|
273
|
+
berksfile = Berksfile.new(manifest['berksfile']) if manifest.include?('berksfile')
|
274
|
+
if berksfile
|
275
|
+
cookbooks = Cookbooks.new(manifest['cookbooks'], berksfile.cookbook_list)
|
276
|
+
create = berksfile.create + cookbooks.create
|
277
|
+
delete = berksfile.delete + cookbooks.delete
|
278
|
+
else
|
279
|
+
cookbooks = Cookbooks.new(manifest['cookbooks'])
|
280
|
+
create = cookbooks.create
|
281
|
+
delete = cookbooks.delete
|
282
|
+
end
|
283
|
+
environments = Environments.new(manifest['environments'], cookbooks)
|
284
|
+
roles = Roles.new(manifest['roles'], environments, cookbooks)
|
285
|
+
data_bags = DataBags.new(manifest['data bags'])
|
286
|
+
nodes = Nodes.new(manifest['nodes'], cookbooks, environments, roles)
|
287
|
+
clusters = Clusters.new(manifest['clusters'], cookbooks, environments, roles)
|
288
|
+
|
289
|
+
create += environments.create + roles.create + data_bags.create + nodes.create + clusters.create
|
290
|
+
delete += environments.delete + roles.delete + data_bags.delete + nodes.delete + clusters.delete
|
291
|
+
return create, delete
|
292
|
+
end
|
293
|
+
|
265
294
|
end
|
266
295
|
end
|
data/lib/spiceweasel/clusters.rb
CHANGED
@@ -34,13 +34,19 @@ module Spiceweasel
|
|
34
34
|
node_name = node.keys.first
|
35
35
|
run_list = node[node_name]['run_list'] || ''
|
36
36
|
options = node[node_name]['options'] || ''
|
37
|
-
# cluster tag is the cluster name + runlist
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
# cluster tag is the cluster name + runlist once tags are working for every plugin
|
38
|
+
# until then, we're going to override the Environment
|
39
|
+
if options =~ /-E/ #delete any Environment
|
40
|
+
env = options.split('-E')[1].split[0]
|
41
|
+
edel = "-E#{env}"
|
42
|
+
options[edel] = "" if options.include?(edel)
|
43
|
+
edel = "-E #{env}"
|
44
|
+
options[edel] = "" if options.include?(edel)
|
45
|
+
Spiceweasel::Log.warn("deleting specified Environment '#{env}' from cluster: '#{cluster_name}'")
|
46
|
+
end
|
47
|
+
#push the Environment back on the options
|
48
|
+
node[node_name]['options'] = options + " -E #{cluster_name}"
|
42
49
|
end
|
43
|
-
Spiceweasel::Log.debug("cluster2: '#{cluster_name}' '#{cluster[cluster_name]}'")
|
44
50
|
# let's reuse the Nodes logic
|
45
51
|
nodes = Spiceweasel::Nodes.new(cluster[cluster_name], cookbooks, environments, roles)
|
46
52
|
@create.concat(nodes.create)
|
@@ -32,6 +32,8 @@ module Spiceweasel
|
|
32
32
|
@dependencies = Array.new
|
33
33
|
#validate each of the cookbooks specified in the manifest
|
34
34
|
if cookbooks
|
35
|
+
@loader = Chef::CookbookLoader.new(Spiceweasel::Config[:cookbook_dir])
|
36
|
+
@loader.load_cookbooks
|
35
37
|
Spiceweasel::Log.debug("cookbooks: #{cookbooks}")
|
36
38
|
|
37
39
|
c_names = []
|
@@ -43,7 +45,8 @@ module Spiceweasel
|
|
43
45
|
end
|
44
46
|
Spiceweasel::Log.debug("cookbook: #{name} #{version} #{options}")
|
45
47
|
if File.directory?("cookbooks")
|
46
|
-
|
48
|
+
|
49
|
+
if @loader.cookbooks_by_name[name]
|
47
50
|
validateMetadata(name,version) unless Spiceweasel::Config[:novalidation]
|
48
51
|
else
|
49
52
|
if Spiceweasel::Config[:siteinstall] #use knife cookbook site install
|
@@ -81,9 +84,7 @@ module Spiceweasel
|
|
81
84
|
#check the metadata for versions and gather deps
|
82
85
|
def validateMetadata(cookbook,version)
|
83
86
|
#check metadata.rb for requested version
|
84
|
-
|
85
|
-
metadata = Chef::Cookbook::Metadata.new
|
86
|
-
metadata.from_file(metadata_file)
|
87
|
+
metadata = @loader.cookbooks_by_name[cookbook].metadata
|
87
88
|
Spiceweasel::Log.debug("validateMetadata: #{cookbook} #{metadata.name} #{metadata.version}")
|
88
89
|
# Should the cookbook directory match the name in the metadata?
|
89
90
|
if metadata.name.empty?
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Matt Ray (<matt@opscode.com>)
|
3
3
|
#
|
4
|
-
# Copyright:: 2011-
|
4
|
+
# Copyright:: 2011-2013, 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.
|
@@ -56,17 +56,23 @@ module Spiceweasel
|
|
56
56
|
items.each do |item|
|
57
57
|
Spiceweasel::Log.debug("data bag #{db} item: #{item}")
|
58
58
|
if item =~ /\*/ #wildcard support, will fail if directory not present
|
59
|
-
files = Dir.glob("data_bags/#{db}
|
60
|
-
|
61
|
-
|
59
|
+
files = Dir.glob("data_bags/#{db}/#{item}")
|
60
|
+
#remove anything not ending in .json
|
61
|
+
files.delete_if {|x| !x.end_with?('.json')}
|
62
|
+
items.concat(files.collect {|x| x["data_bags/#{db}/".length..-6]})
|
63
|
+
Spiceweasel::Log.debug("found files '#{files}' for data bag: #{db} with wildcard #{item}")
|
62
64
|
next
|
63
65
|
end
|
64
66
|
validateItem(db, item) unless Spiceweasel::Config[:novalidation]
|
65
67
|
end
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
68
|
+
items.delete_if {|x| x.include?("*")} #remove wildcards
|
69
|
+
items.sort!.uniq!
|
70
|
+
unless items.empty?
|
71
|
+
if secret
|
72
|
+
create_command("knife data bag#{Spiceweasel::Config[:knife_options]} from file #{db} #{items.join('.json ')}.json --secret-file #{secret}")
|
73
|
+
else
|
74
|
+
create_command("knife data bag#{Spiceweasel::Config[:knife_options]} from file #{db} #{items.join('.json ')}.json")
|
75
|
+
end
|
70
76
|
end
|
71
77
|
end
|
72
78
|
end
|
@@ -81,6 +87,9 @@ module Spiceweasel
|
|
81
87
|
f = File.read("data_bags/#{db}/#{item}.json")
|
82
88
|
itemfile = JSON.parse(f) #invalid JSON will throw a trace
|
83
89
|
#validate the id matches the file name
|
90
|
+
if item =~ /\// #pull out directories
|
91
|
+
item = item.split('/').last
|
92
|
+
end
|
84
93
|
if !item.eql?(itemfile['id'])
|
85
94
|
STDERR.puts "ERROR: data bag '#{db}' item '#{item}' listed in the manifest does not match the id '#{itemfile['id']}' within the 'data_bags/#{db}/#{item}.json' file."
|
86
95
|
exit(-1)
|
@@ -31,31 +31,43 @@ module Spiceweasel
|
|
31
31
|
@environment_list = Array.new
|
32
32
|
if environments
|
33
33
|
Spiceweasel::Log.debug("environments: #{environments}")
|
34
|
+
flatenvs = environments.collect {|x| x.keys}.flatten
|
34
35
|
envfiles = []
|
35
|
-
|
36
|
-
|
37
|
-
Spiceweasel::Log.debug("environment: #{name}")
|
36
|
+
flatenvs.each do |env|
|
37
|
+
Spiceweasel::Log.debug("environment: #{env}")
|
38
38
|
if File.directory?("environments")
|
39
|
-
|
39
|
+
#expand wildcards and push into environments
|
40
|
+
if env =~ /\*/ #wildcard support
|
41
|
+
wildenvs = Dir.glob("environments/#{env}")
|
42
|
+
#remove anything not ending in .json or .rb
|
43
|
+
wildenvs.delete_if {|x| !x.end_with?(".rb", ".json")}
|
44
|
+
Spiceweasel::Log.debug("found environments '#{wildenvs}' for wildcard: #{env}")
|
45
|
+
flatenvs.concat(wildenvs.collect {|x| x[x.rindex('/')+1..x.rindex('.')-1]})
|
46
|
+
next
|
47
|
+
end
|
48
|
+
validate(env, cookbooks) unless Spiceweasel::Config[:novalidation]
|
40
49
|
elsif !Spiceweasel::Config[:novalidation]
|
41
50
|
STDERR.puts "'environments' directory not found, unable to validate or load environments"
|
42
51
|
exit(-1)
|
43
52
|
end
|
44
|
-
if File.exists?("environments/#{
|
45
|
-
envfiles.push("#{
|
53
|
+
if File.exists?("environments/#{env}.json")
|
54
|
+
envfiles.push("#{env}.json")
|
46
55
|
else #assume no .json means they want .rb and catchall for misssing dir
|
47
|
-
envfiles.push("#{
|
56
|
+
envfiles.push("#{env}.rb")
|
48
57
|
end
|
49
|
-
delete_command("knife environment#{Spiceweasel::Config[:knife_options]} delete #{
|
50
|
-
@environment_list.push(
|
58
|
+
delete_command("knife environment#{Spiceweasel::Config[:knife_options]} delete #{env} -y")
|
59
|
+
@environment_list.push(env)
|
51
60
|
end
|
52
|
-
create_command("knife environment#{Spiceweasel::Config[:knife_options]} from file #{envfiles.join(' ')}")
|
61
|
+
create_command("knife environment#{Spiceweasel::Config[:knife_options]} from file #{envfiles.uniq.sort.join(' ')}")
|
53
62
|
end
|
54
63
|
end
|
55
64
|
|
56
65
|
#validate the content of the environment file
|
57
66
|
def validate(environment, cookbooks)
|
58
67
|
file = %W(environments/#{environment}.rb environments/#{environment}.json).detect{|f| File.exists?(f)}
|
68
|
+
if environment =~ /\// #pull out directories
|
69
|
+
environment = environment.split('/').last
|
70
|
+
end
|
59
71
|
if file
|
60
72
|
case file
|
61
73
|
when /\.json$/
|
@@ -89,7 +89,7 @@ module Spiceweasel
|
|
89
89
|
|
90
90
|
def self.resolve_cookbooks(berkshelf_cookbooks = {})
|
91
91
|
require 'solve'
|
92
|
-
loader = Chef::CookbookLoader.new(
|
92
|
+
loader = Chef::CookbookLoader.new(Spiceweasel::Config[:cookbook_dir])
|
93
93
|
loader.load_cookbooks
|
94
94
|
books = loader.cookbooks_by_name
|
95
95
|
graph = Solve::Graph.new
|
data/lib/spiceweasel/roles.rb
CHANGED
@@ -37,6 +37,15 @@ module Spiceweasel
|
|
37
37
|
flatroles.each do |role|
|
38
38
|
Spiceweasel::Log.debug("role: #{role}")
|
39
39
|
if File.directory?("roles")
|
40
|
+
#expand wildcards and push into flatroles
|
41
|
+
if role =~ /\*/ #wildcard support
|
42
|
+
wildroles = Dir.glob("roles/#{role}")
|
43
|
+
#remove anything not ending in .json or .rb
|
44
|
+
wildroles.delete_if {|x| !x.end_with?(".rb", ".json")}
|
45
|
+
Spiceweasel::Log.debug("found roles '#{wildroles}' for wildcard: #{role}")
|
46
|
+
flatroles.concat(wildroles.collect {|x| x[x.rindex('/')+1..x.rindex('.')-1]})
|
47
|
+
next
|
48
|
+
end
|
40
49
|
validate(role, environments, cookbooks, flatroles) unless Spiceweasel::Config[:novalidation]
|
41
50
|
elsif !Spiceweasel::Config[:novalidation]
|
42
51
|
STDERR.puts "ERROR: 'roles' directory not found, unable to validate or load roles"
|
@@ -50,7 +59,7 @@ module Spiceweasel
|
|
50
59
|
delete_command("knife role#{Spiceweasel::Config[:knife_options]} delete #{role} -y")
|
51
60
|
@role_list.push(role)
|
52
61
|
end
|
53
|
-
create_command("knife role#{Spiceweasel::Config[:knife_options]} from file #{rolefiles.join(' ')}")
|
62
|
+
create_command("knife role#{Spiceweasel::Config[:knife_options]} from file #{rolefiles.uniq.sort.join(' ')}")
|
54
63
|
end
|
55
64
|
end
|
56
65
|
|
@@ -58,7 +67,10 @@ module Spiceweasel
|
|
58
67
|
def validate(role, environments, cookbooks, roles)
|
59
68
|
#validate the role passed in match the name of either the .rb or .json
|
60
69
|
file = %W(roles/#{role}.rb roles/#{role}.json).detect{|f| File.exists?(f)}
|
61
|
-
if
|
70
|
+
if role =~ /\// #pull out directories
|
71
|
+
role = role.split('/').last
|
72
|
+
end
|
73
|
+
if file
|
62
74
|
case file
|
63
75
|
when /\.json$/
|
64
76
|
c_role = Chef::JSONCompat.from_json(IO.read(file))
|
data/lib/spiceweasel/version.rb
CHANGED
@@ -36,12 +36,11 @@ knife node bulk delete .* -y
|
|
36
36
|
knife cookbook upload apache2
|
37
37
|
knife cookbook upload apt --freeze
|
38
38
|
knife cookbook upload mysql ntp
|
39
|
-
knife environment from file development.rb
|
39
|
+
knife environment from file development.rb production.rb qa.rb
|
40
40
|
knife role from file base.rb iisserver.rb monitoring.rb webserver.rb
|
41
41
|
knife data bag create users
|
42
42
|
knife data bag from file users alice.json bob.json chuck.json
|
43
43
|
knife data bag create data
|
44
|
-
knife data bag from file data *.json
|
45
44
|
knife data bag create passwords
|
46
45
|
knife data bag from file passwords mysql.json rabbitmq.json --secret-file secret_key
|
47
46
|
knife bootstrap serverA -i ~/.ssh/mray.pem -x user --sudo -r 'role[base]'
|
@@ -53,10 +52,10 @@ knife rackspace server create --image 49 --flavor 2 -N db3 -r 'recipe[mysql],rol
|
|
53
52
|
knife bootstrap windows winrm winboxA -x Administrator -P 'super_secret_password' -r 'role[base],role[iisserver]'
|
54
53
|
knife bootstrap windows ssh winboxB -x Administrator -P 'super_secret_password' -r 'role[base],role[iisserver]'
|
55
54
|
knife bootstrap windows ssh winboxC -x Administrator -P 'super_secret_password' -r 'role[base],role[iisserver]'
|
56
|
-
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-8af0f326 -f m1.medium -
|
57
|
-
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -
|
58
|
-
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -
|
59
|
-
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -
|
55
|
+
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-8af0f326 -f m1.medium -E amazon -r 'role[mysql]'
|
56
|
+
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -E amazon -r 'role[webserver],recipe[mysql::client]'
|
57
|
+
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -E amazon -r 'role[webserver],recipe[mysql::client]'
|
58
|
+
knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7000f019 -f m1.small -E amazon -r 'role[webserver],recipe[mysql::client]'
|
60
59
|
OUTPUT
|
61
60
|
|
62
61
|
@spiceweasel_binary = File.join(File.dirname(__FILE__), *%w[.. .. bin spiceweasel])
|
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: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|