spiceweasel 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +39 -19
- data/lib/spiceweasel/berksfile.rb +59 -0
- data/lib/spiceweasel/cli.rb +25 -10
- data/lib/spiceweasel/command.rb +25 -0
- data/lib/spiceweasel/command_helper.rb +15 -0
- data/lib/spiceweasel/cookbooks.rb +24 -8
- data/lib/spiceweasel/data_bags.rb +9 -7
- data/lib/spiceweasel/environments.rb +19 -34
- data/lib/spiceweasel/execute.rb +2 -3
- data/lib/spiceweasel/extract_local.rb +37 -46
- data/lib/spiceweasel/nodes.rb +44 -17
- data/lib/spiceweasel/roles.rb +33 -59
- data/lib/spiceweasel/version.rb +1 -1
- data/spec/bin/spiceweasel_spec.rb +28 -28
- metadata +37 -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 from a file. It provides a simple syntax in
|
6
|
+
Spiceweasel is a command-line tool for batch loading Chef infrastructure from a file. 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.
|
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,13 +11,13 @@ 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
|
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.
|
15
15
|
|
16
|
-
Written and tested initially with Chef 0.9.12 (may still work) and continuing development with the 10.x series. It is tested with Ruby 1.
|
16
|
+
Written and tested initially with Chef 0.9.12 (may still work) and continuing development with the 10.x series. 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
|
|
20
|
-
The syntax for the Spiceweasel file may be
|
20
|
+
The syntax for the Spiceweasel file may be Ruby, JSON or YAML format of Chef primitives describing what is to be instantiated. Please refer to the [examples/example.json](https://github.com/mattray/spiceweasel/blob/master/examples/example.json) or [examples/example.yml](https://github.com/mattray/spiceweasel/blob/master/examples/example.yml) for examples of the same infrastructure. Each subsection below shows the YAML syntax converted to knife commands.
|
21
21
|
|
22
22
|
## Manifest syntax changes in Spiceweasel 2.0 ##
|
23
23
|
|
@@ -50,6 +50,7 @@ cookbooks:
|
|
50
50
|
version: 1.2.0
|
51
51
|
options: --freeze
|
52
52
|
- mysql:
|
53
|
+
- ntp:
|
53
54
|
```
|
54
55
|
|
55
56
|
produces the knife commands
|
@@ -60,7 +61,35 @@ knife cookbook site download apt 1.2.0 --file cookbooks/apt.tgz
|
|
60
61
|
tar -C cookbooks/ -xf cookbooks/apt.tgz
|
61
62
|
rm -f cookbooks/apt.tgz
|
62
63
|
knife cookbook upload apt --freeze
|
63
|
-
knife cookbook upload mysql
|
64
|
+
knife cookbook upload mysql ntp
|
65
|
+
```
|
66
|
+
|
67
|
+
## Berkshelf ##
|
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 `berkshelf:` 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
|
+
|
71
|
+
``` yaml
|
72
|
+
berkshelf:
|
73
|
+
```
|
74
|
+
|
75
|
+
which produces the command
|
76
|
+
|
77
|
+
```
|
78
|
+
berks upload -b ./Berksfile
|
79
|
+
```
|
80
|
+
|
81
|
+
or you may use additional options like
|
82
|
+
|
83
|
+
``` yaml
|
84
|
+
berksfile:
|
85
|
+
path: '/Users/mray/ws/lab-repo/Berksfile'
|
86
|
+
options: '--skip_syntax_check --config some_config.json'
|
87
|
+
```
|
88
|
+
|
89
|
+
which produces the output
|
90
|
+
|
91
|
+
```
|
92
|
+
berks upload --skip_syntax_check --config some_config.json -b /Users/mray/ws/lab-repo/Berksfile
|
64
93
|
```
|
65
94
|
|
66
95
|
## Environments ##
|
@@ -77,9 +106,7 @@ environments:
|
|
77
106
|
produces the knife commands
|
78
107
|
|
79
108
|
```
|
80
|
-
knife environment from file development.rb
|
81
|
-
knife environment from file qa.rb
|
82
|
-
knife environment from file production.rb
|
109
|
+
knife environment from file development.rb qa.rb production.rb
|
83
110
|
```
|
84
111
|
|
85
112
|
## Roles ##
|
@@ -97,10 +124,7 @@ roles:
|
|
97
124
|
produces the knife commands
|
98
125
|
|
99
126
|
```
|
100
|
-
knife role from file base.rb
|
101
|
-
knife role from file iisserver.rb
|
102
|
-
knife role from file monitoring.rb
|
103
|
-
knife role from file webserver.rb
|
127
|
+
knife role from file base.rb iisserver.rb monitoring.rb webserver.rb
|
104
128
|
```
|
105
129
|
|
106
130
|
n## Data Bags ##
|
@@ -128,15 +152,11 @@ produces the knife commands
|
|
128
152
|
|
129
153
|
```
|
130
154
|
knife data bag create users
|
131
|
-
knife data bag from file users alice.json
|
132
|
-
knife data bag from file users bob.json
|
133
|
-
knife data bag from file users chuck.json
|
155
|
+
knife data bag from file users alice.json bob.json chuck.json
|
134
156
|
knife data bag create data
|
135
|
-
knife data bag from file data
|
136
|
-
knife data bag from file data dataB.json
|
157
|
+
knife data bag from file data *.json
|
137
158
|
knife data bag create passwords
|
138
|
-
knife data bag from file passwords mysql.json --secret-file secret_key_filename
|
139
|
-
knife data bag from file passwords rabbitmq.json --secret-file secret_key_filename
|
159
|
+
knife data bag from file passwords mysql.json rabbitmq.json --secret-file secret_key_filename
|
140
160
|
```
|
141
161
|
|
142
162
|
## Nodes ##
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Ray (<matt@opscode.com>)
|
3
|
+
#
|
4
|
+
# Copyright:: 2013, Opscode, Inc <legal@opscode.com>
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
module Spiceweasel
|
20
|
+
class Berksfile
|
21
|
+
|
22
|
+
attr_reader :create
|
23
|
+
attr_reader :delete
|
24
|
+
attr_reader :cookbook_list
|
25
|
+
|
26
|
+
include CommandHelper
|
27
|
+
|
28
|
+
def initialize(berkshelf=nil)
|
29
|
+
@create = []
|
30
|
+
@delete = []
|
31
|
+
@cookbook_list = {}
|
32
|
+
# only load berkshelf if we are going to use it
|
33
|
+
require 'berkshelf'
|
34
|
+
berks_options = []
|
35
|
+
case berkshelf
|
36
|
+
when String
|
37
|
+
path = berkshelf
|
38
|
+
when Hash
|
39
|
+
path = berkshelf['path']
|
40
|
+
berks_options << berkshelf['options'] if berkshelf['options']
|
41
|
+
end
|
42
|
+
path ||= './Berksfile'
|
43
|
+
berks_options << "-b #{path}"
|
44
|
+
berks_options = berks_options.join(' ')
|
45
|
+
opts = Thor::Options.split(berks_options.split(' ')).last
|
46
|
+
resolve_opts = Thor::Options.new(Berkshelf::Cli.tasks['upload'].options).parse(opts)
|
47
|
+
berks = Berkshelf::Berksfile.from_file(path)
|
48
|
+
create_command("berks upload #{berks_options}")
|
49
|
+
Berkshelf.ui.mute do
|
50
|
+
Spiceweasel::Log.debug("berkshelf resolving dependencies: #{resolve_opts}")
|
51
|
+
berks.resolve(resolve_opts).each do |cb|
|
52
|
+
@cookbook_list[cb.cookbook_name] = cb.version
|
53
|
+
delete_command("knife cookbook#{Spiceweasel::Config[:knife_options]} delete #{cb.cookbook_name} #{cb.version} -a -y")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
data/lib/spiceweasel/cli.rb
CHANGED
@@ -21,7 +21,9 @@ require 'json'
|
|
21
21
|
require 'yaml'
|
22
22
|
|
23
23
|
require 'spiceweasel'
|
24
|
+
require 'spiceweasel/command_helper'
|
24
25
|
require 'spiceweasel/cookbooks'
|
26
|
+
require 'spiceweasel/berksfile'
|
25
27
|
require 'spiceweasel/environments'
|
26
28
|
require 'spiceweasel/roles'
|
27
29
|
require 'spiceweasel/data_bags'
|
@@ -130,6 +132,10 @@ module Spiceweasel
|
|
130
132
|
:proc => lambda { |v| puts "Spiceweasel: #{::Spiceweasel::VERSION}" },
|
131
133
|
:exit => 0
|
132
134
|
|
135
|
+
option :unique_id,
|
136
|
+
:long => '--unique-id UID',
|
137
|
+
:description => 'Unique ID generally used for ruby based configs'
|
138
|
+
|
133
139
|
def run
|
134
140
|
if Spiceweasel::Config[:extractlocal] || Spiceweasel::Config[:extractjson] || Spiceweasel::Config[:extractyaml]
|
135
141
|
manifest = Spiceweasel::ExtractLocal.parse_objects
|
@@ -143,19 +149,24 @@ module Spiceweasel
|
|
143
149
|
end
|
144
150
|
Spiceweasel::Log.debug("file manifest: #{manifest}")
|
145
151
|
|
146
|
-
|
152
|
+
berksfile = Berksfile.new(manifest['berksfile']) if manifest.include?('berksfile')
|
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
|
147
162
|
environments = Environments.new(manifest['environments'], cookbooks)
|
148
163
|
roles = Roles.new(manifest['roles'], environments, cookbooks)
|
149
164
|
data_bags = DataBags.new(manifest['data bags'])
|
150
165
|
nodes = Nodes.new(manifest['nodes'], cookbooks, environments, roles)
|
151
166
|
clusters = Clusters.new(manifest['clusters'], cookbooks, environments, roles)
|
152
167
|
|
153
|
-
create
|
154
|
-
delete
|
155
|
-
|
156
|
-
#trim trailing whitespace
|
157
|
-
create.each {|x| x.rstrip!}
|
158
|
-
delete.each {|x| x.rstrip!}
|
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
|
159
170
|
|
160
171
|
if Spiceweasel::Config[:extractjson]
|
161
172
|
puts JSON.pretty_generate(manifest)
|
@@ -227,8 +238,11 @@ module Spiceweasel
|
|
227
238
|
output = YAML.load_file(file)
|
228
239
|
elsif (file.end_with?(".json"))
|
229
240
|
output = JSON.parse(File.read(file))
|
241
|
+
elsif (file.end_with?(".rb"))
|
242
|
+
output = self.instance_eval(IO.read(file), file, 1)
|
243
|
+
output = JSON.parse(JSON.dump(output))
|
230
244
|
else
|
231
|
-
STDERR.puts "ERROR: #{file} is an unknown file type, please use a file ending with
|
245
|
+
STDERR.puts "ERROR: #{file} is an unknown file type, please use a file ending with '.rb', '.json' or '.yml'."
|
232
246
|
exit(-1)
|
233
247
|
end
|
234
248
|
rescue Psych::SyntaxError => e
|
@@ -239,8 +253,9 @@ module Spiceweasel
|
|
239
253
|
STDERR.puts e.message
|
240
254
|
STDERR.puts "ERROR: Parsing error in #{file}."
|
241
255
|
exit(-1)
|
242
|
-
rescue Exception
|
243
|
-
STDERR.puts "ERROR:
|
256
|
+
rescue Exception => e
|
257
|
+
STDERR.puts "ERROR: Invalid or missing manifest .json, .rb, or .yml file provided."
|
258
|
+
STDERR.puts "ERROR: #{e}"
|
244
259
|
puts opt_parser.to_s
|
245
260
|
exit(-1)
|
246
261
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Spiceweasel
|
2
|
+
class Command
|
3
|
+
|
4
|
+
attr_reader :allow_failure
|
5
|
+
attr_reader :timeout
|
6
|
+
attr_reader :command
|
7
|
+
|
8
|
+
def initialize(command, options={})
|
9
|
+
@command = command.rstrip
|
10
|
+
@options = options
|
11
|
+
@timeout = options['timeout']
|
12
|
+
@allow_failure = options.has_key?('allow_failure') ? options['allow_failure'] : true
|
13
|
+
end
|
14
|
+
|
15
|
+
def shellout_opts
|
16
|
+
opts = {}
|
17
|
+
opts[:timeout] = timeout if timeout
|
18
|
+
opts
|
19
|
+
end
|
20
|
+
|
21
|
+
alias_method :allow_failure?, :allow_failure
|
22
|
+
alias_method :to_s, :command
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spiceweasel/command'
|
2
|
+
|
3
|
+
module Spiceweasel
|
4
|
+
module CommandHelper
|
5
|
+
def create_command(*args)
|
6
|
+
@create ||= []
|
7
|
+
@create.push(Command.new(*args))
|
8
|
+
end
|
9
|
+
|
10
|
+
def delete_command(*args)
|
11
|
+
@delete ||= []
|
12
|
+
@delete.push(Command.new(*args))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -21,16 +21,20 @@ require 'chef/cookbook/metadata'
|
|
21
21
|
module Spiceweasel
|
22
22
|
class Cookbooks
|
23
23
|
|
24
|
+
include CommandHelper
|
25
|
+
|
24
26
|
attr_reader :cookbook_list, :create, :delete
|
25
27
|
|
26
|
-
def initialize(cookbooks = [])
|
28
|
+
def initialize(cookbooks = [], other_cookbook_list = {})
|
27
29
|
@create = Array.new
|
28
30
|
@delete = Array.new
|
29
|
-
@cookbook_list =
|
31
|
+
@cookbook_list = other_cookbook_list
|
30
32
|
@dependencies = Array.new
|
31
33
|
#validate each of the cookbooks specified in the manifest
|
32
34
|
if cookbooks
|
33
35
|
Spiceweasel::Log.debug("cookbooks: #{cookbooks}")
|
36
|
+
|
37
|
+
c_names = []
|
34
38
|
cookbooks.each do |cookbook|
|
35
39
|
name = cookbook.keys.first
|
36
40
|
if cookbook[name]
|
@@ -43,21 +47,33 @@ module Spiceweasel
|
|
43
47
|
validateMetadata(name,version) unless Spiceweasel::Config[:novalidation]
|
44
48
|
else
|
45
49
|
if Spiceweasel::Config[:siteinstall] #use knife cookbook site install
|
46
|
-
|
50
|
+
create_command("knife cookbook#{Spiceweasel::Config[:knife_options]} site install #{name} #{version} #{options}")
|
47
51
|
else #use knife cookbook site download, untar and then remove the tarball
|
48
|
-
|
49
|
-
|
50
|
-
|
52
|
+
create_command("knife cookbook#{Spiceweasel::Config[:knife_options]} site download #{name} #{version} --file cookbooks/#{name}.tgz #{options}")
|
53
|
+
create_command("tar -C cookbooks/ -xf cookbooks/#{name}.tgz")
|
54
|
+
create_command("rm -f cookbooks/#{name}.tgz")
|
51
55
|
end
|
52
56
|
end
|
53
57
|
elsif !Spiceweasel::Config[:novalidation]
|
54
58
|
STDERR.puts "ERROR: 'cookbooks' directory not found, unable to validate, download and load cookbooks"
|
55
59
|
exit(-1)
|
56
60
|
end
|
57
|
-
|
58
|
-
|
61
|
+
|
62
|
+
if(options)
|
63
|
+
if !c_names.empty?
|
64
|
+
create_command("knife cookbook#{Spiceweasel::Config[:knife_options]} upload #{c_names.join(' ')}")
|
65
|
+
c_names = []
|
66
|
+
end
|
67
|
+
create_command("knife cookbook#{Spiceweasel::Config[:knife_options]} upload #{name} #{options}")
|
68
|
+
else
|
69
|
+
c_names.push(name)
|
70
|
+
end
|
71
|
+
delete_command("knife cookbook#{Spiceweasel::Config[:knife_options]} delete #{name} #{version} -a -y")
|
59
72
|
@cookbook_list[name] = version #used for validation
|
60
73
|
end
|
74
|
+
if !c_names.empty?
|
75
|
+
create_command("knife cookbook#{Spiceweasel::Config[:knife_options]} upload #{c_names.join(' ')}")
|
76
|
+
end
|
61
77
|
validateDependencies() unless Spiceweasel::Config[:novalidation]
|
62
78
|
end
|
63
79
|
end
|
@@ -21,6 +21,8 @@ require 'json'
|
|
21
21
|
module Spiceweasel
|
22
22
|
class DataBags
|
23
23
|
|
24
|
+
include CommandHelper
|
25
|
+
|
24
26
|
attr_reader :create, :delete
|
25
27
|
|
26
28
|
def initialize(data_bags = [])
|
@@ -39,8 +41,8 @@ module Spiceweasel
|
|
39
41
|
STDERR.puts "ERROR: 'data_bags/#{db}' directory not found, unable to validate or load data bag items"
|
40
42
|
exit(-1)
|
41
43
|
end
|
42
|
-
|
43
|
-
|
44
|
+
create_command("knife data bag#{Spiceweasel::Config[:knife_options]} create #{db}")
|
45
|
+
delete_command("knife data bag#{Spiceweasel::Config[:knife_options]} delete #{db} -y")
|
44
46
|
if data_bag[db]
|
45
47
|
items = data_bag[db]['items']
|
46
48
|
secret = data_bag[db]['secret']
|
@@ -60,11 +62,11 @@ module Spiceweasel
|
|
60
62
|
next
|
61
63
|
end
|
62
64
|
validateItem(db, item) unless Spiceweasel::Config[:novalidation]
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
end
|
66
|
+
if secret
|
67
|
+
create_command("knife data bag#{Spiceweasel::Config[:knife_options]} from file #{db} #{items.join('.json ')}.json --secret-file #{secret}")
|
68
|
+
else
|
69
|
+
create_command("knife data bag#{Spiceweasel::Config[:knife_options]} from file #{db} #{items.join('.json ')}.json")
|
68
70
|
end
|
69
71
|
end
|
70
72
|
end
|
@@ -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.
|
@@ -21,6 +21,8 @@ require 'json'
|
|
21
21
|
module Spiceweasel
|
22
22
|
class Environments
|
23
23
|
|
24
|
+
include CommandHelper
|
25
|
+
|
24
26
|
attr_reader :environment_list, :create, :delete
|
25
27
|
|
26
28
|
def initialize(environments = [], cookbooks = {})
|
@@ -29,6 +31,7 @@ module Spiceweasel
|
|
29
31
|
@environment_list = Array.new
|
30
32
|
if environments
|
31
33
|
Spiceweasel::Log.debug("environments: #{environments}")
|
34
|
+
envfiles = []
|
32
35
|
environments.each do |env|
|
33
36
|
name = env.keys[0]
|
34
37
|
Spiceweasel::Log.debug("environment: #{name}")
|
@@ -39,56 +42,38 @@ module Spiceweasel
|
|
39
42
|
exit(-1)
|
40
43
|
end
|
41
44
|
if File.exists?("environments/#{name}.json")
|
42
|
-
|
45
|
+
envfiles.push("#{name}.json")
|
43
46
|
else #assume no .json means they want .rb and catchall for misssing dir
|
44
|
-
|
47
|
+
envfiles.push("#{name}.rb")
|
45
48
|
end
|
46
|
-
|
49
|
+
delete_command("knife environment#{Spiceweasel::Config[:knife_options]} delete #{name} -y")
|
47
50
|
@environment_list.push(name)
|
48
51
|
end
|
52
|
+
create_command("knife environment#{Spiceweasel::Config[:knife_options]} from file #{envfiles.join(' ')}")
|
49
53
|
end
|
50
54
|
end
|
51
55
|
|
52
56
|
#validate the content of the environment file
|
53
57
|
def validate(environment, cookbooks)
|
54
|
-
|
55
|
-
if
|
56
|
-
|
57
|
-
|
58
|
-
|
58
|
+
file = %W(environments/#{environment}.rb environments/#{environment}.json).detect{|f| File.exists?(f)}
|
59
|
+
if file
|
60
|
+
if (Chef::Version.new(Chef::VERSION) < Chef::Version.new('11.0.0'))
|
61
|
+
env = Chef::Environment.new(false)
|
62
|
+
else
|
63
|
+
env = Chef::Environment.new
|
64
|
+
end
|
65
|
+
env.from_file(file)
|
66
|
+
if(env.name != environment)
|
59
67
|
STDERR.puts "ERROR: Environment '#{environment}' listed in the manifest does not match the name '#{name}' within the environments/#{environment}.rb file."
|
60
68
|
exit(-1)
|
61
69
|
end
|
62
|
-
|
63
|
-
envcookbooks = File.open("environments/#{environment}.rb").grep(/^cookbook /)
|
64
|
-
envcookbooks.each do |cb|
|
65
|
-
dep = cb.split()[1].gsub(/"/,'').gsub(/,/,'')
|
70
|
+
env.cookbook_versions.keys.each do |dep|
|
66
71
|
Spiceweasel::Log.debug("environment: '#{environment}' cookbook: '#{dep}'")
|
67
|
-
|
72
|
+
unless cookbooks.member?(dep)
|
68
73
|
STDERR.puts "ERROR: Cookbook dependency '#{dep}' from environment '#{environment}' is missing from the list of cookbooks in the manifest."
|
69
74
|
exit(-1)
|
70
75
|
end
|
71
76
|
end
|
72
|
-
elsif File.exists?("environments/#{environment}.json")
|
73
|
-
#load the json, don't symbolize since we don't need json_class
|
74
|
-
f = File.read("environments/#{environment}.json")
|
75
|
-
JSON.create_id = nil
|
76
|
-
envfile = JSON.parse(f, {:symbolize_names => false})
|
77
|
-
Spiceweasel::Log.debug("environment: '#{environment}' file: '#{envfile}'")
|
78
|
-
#validate that the name inside the file matches
|
79
|
-
Spiceweasel::Log.debug("environment: '#{environment}' name: '#{envfile['name']}'")
|
80
|
-
if !environment.eql?(envfile['name'])
|
81
|
-
STDERR.puts "ERROR: Environment '#{environment}' listed in the manifest does not match the name '#{envfile['name']}' within the 'environments/#{environment}.json' file."
|
82
|
-
exit(-1)
|
83
|
-
end
|
84
|
-
#validate the cookbooks exist if they're mentioned
|
85
|
-
envfile['cookbook_versions'].keys.each do |cb|
|
86
|
-
Spiceweasel::Log.debug("environment: '#{environment}' cookbook: '#{cb}'")
|
87
|
-
if !cookbooks.member?(cb.to_s)
|
88
|
-
STDERR.puts "ERROR: Cookbook dependency '#{cb}' from environment '#{environment}' is missing from the list of cookbooks in the manifest."
|
89
|
-
exit(-1)
|
90
|
-
end
|
91
|
-
end
|
92
77
|
else #environment is not here
|
93
78
|
STDERR.puts "ERROR: Invalid Environment '#{environment}' listed in the manifest but not found in the environments directory."
|
94
79
|
exit(-1)
|
data/lib/spiceweasel/execute.rb
CHANGED
@@ -25,15 +25,14 @@ module Spiceweasel
|
|
25
25
|
def initialize(commands)
|
26
26
|
# for now we're shelling out
|
27
27
|
commands.each do | cmd |
|
28
|
-
knife = Mixlib::ShellOut.new(cmd)
|
28
|
+
knife = Mixlib::ShellOut.new(cmd.command, cmd.shellout_opts.merge(:live_stream => STDOUT))
|
29
29
|
# check for parallel? and eventually use threads
|
30
30
|
knife.run_command
|
31
|
-
puts cmd
|
32
|
-
puts knife.stdout
|
33
31
|
puts knife.stderr
|
34
32
|
Spiceweasel::Log.debug(cmd)
|
35
33
|
Spiceweasel::Log.debug(knife.stdout)
|
36
34
|
Spiceweasel::Log.fatal(knife.stderr) if !knife.stderr.empty?
|
35
|
+
find.error! unless cmd.allow_failure?
|
37
36
|
end
|
38
37
|
end
|
39
38
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# Author:: Geoff Meakin
|
3
3
|
# Author:: Matt Ray (<matt@opscode.com>)
|
4
4
|
#
|
5
|
-
# Copyright:: 2012, Opscode, Inc <legal@opscode.com>
|
5
|
+
# Copyright:: 2012-2013, Opscode, Inc <legal@opscode.com>
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
8
|
# you may not use this file except in compliance with the License.
|
@@ -17,27 +17,22 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require 'chef
|
20
|
+
require 'chef'
|
21
21
|
|
22
22
|
module Spiceweasel
|
23
23
|
class ExtractLocal
|
24
24
|
|
25
25
|
def self.parse_objects
|
26
|
-
objects = {
|
26
|
+
objects = {}
|
27
27
|
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
metadata.from_file("#{cookbook_full_path}/metadata.rb")
|
33
|
-
if metadata.name.empty?
|
34
|
-
Spiceweasel::Log.fatal("No cookbook name in the #{cookbook_full_path}/metadata.rb.")
|
35
|
-
exit(-1)
|
36
|
-
end
|
37
|
-
Spiceweasel::Log.debug("dir_ext: #{metadata.name} #{metadata.version}")
|
38
|
-
cookbooks.push(metadata)
|
28
|
+
# BERKSHELF
|
29
|
+
if File.file?('./Berksfile')
|
30
|
+
objects['berksfile'] = nil
|
31
|
+
berksfile = Berksfile.new(objects['berksfile'])
|
39
32
|
end
|
40
|
-
|
33
|
+
|
34
|
+
# COOKBOOKS
|
35
|
+
cookbooks = self.resolve_cookbooks(berksfile.cookbook_list)
|
41
36
|
objects['cookbooks'] = cookbooks unless cookbooks.empty?
|
42
37
|
|
43
38
|
# ROLES
|
@@ -80,7 +75,6 @@ module Spiceweasel
|
|
80
75
|
# nodes << {node => nil}
|
81
76
|
# end
|
82
77
|
# objects['nodes'] = nodes unless nodes.empty?
|
83
|
-
|
84
78
|
objects
|
85
79
|
end
|
86
80
|
|
@@ -92,39 +86,36 @@ module Spiceweasel
|
|
92
86
|
name.join('.')
|
93
87
|
end
|
94
88
|
|
95
|
-
def self.
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
Spiceweasel::Log.debug("dir_ext:
|
105
|
-
|
106
|
-
if sorted_cookbooks.eql?(sorted_cookbooks | cookbook.dependencies.collect {|x| x[0]})
|
107
|
-
sorted_cookbooks.push(cookbook.name)
|
108
|
-
scount = 0
|
109
|
-
else #put it back in the list
|
110
|
-
unsorted_cookbooks.push(cookbook)
|
111
|
-
scount = scount + 1
|
112
|
-
end
|
113
|
-
Spiceweasel::Log.debug("dir_ext: sorted_cookbooks: '#{sorted_cookbooks}' #{scount}")
|
89
|
+
def self.resolve_cookbooks(berkshelf_cookbooks = {})
|
90
|
+
require 'solve'
|
91
|
+
loader = Chef::CookbookLoader.new('./cookbooks')
|
92
|
+
loader.load_cookbooks
|
93
|
+
books = loader.cookbooks_by_name
|
94
|
+
graph = Solve::Graph.new
|
95
|
+
cblist = []
|
96
|
+
#push in the berkshelf cookbooks to cover any other deps
|
97
|
+
berkshelf_cookbooks.each do |name, version|
|
98
|
+
Spiceweasel::Log.debug("dir_ext:berks: #{name} #{version}")
|
99
|
+
graph.artifacts(name, version)
|
114
100
|
end
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
deps = unsorted_cookbooks.collect {|x| x.dependencies.collect {|x| x[0]} - sorted_cookbooks}
|
122
|
-
STDERR.puts "ERROR: Dependencies not satisfied or circular dependencies in cookbook(s): #{remainders} depend(s) on #{deps}"
|
123
|
-
exit(-1)
|
101
|
+
books.each do |name, cb|
|
102
|
+
Spiceweasel::Log.debug("dir_ext: #{name} #{cb.version}")
|
103
|
+
artifact = graph.artifacts(name, cb.version)
|
104
|
+
cblist.push([name, cb.version])
|
105
|
+
cb.metadata.dependencies.each do |dep_name, dep_version|
|
106
|
+
artifact.depends(dep_name, dep_version)
|
124
107
|
end
|
125
108
|
end
|
126
|
-
#
|
127
|
-
|
109
|
+
#get the cookbooks and their versions, map to cookbook hash format
|
110
|
+
begin
|
111
|
+
cookbooks = []
|
112
|
+
Solve.it!(graph, cblist).each {|k,v| cookbooks.push({k => {'version' => v}})}
|
113
|
+
rescue Solve::Errors::NoSolutionError => e
|
114
|
+
STDERR.puts "ERROR: There are missing cookbook dependencies, please check your metadata.rb files."
|
115
|
+
exit(-1)
|
116
|
+
end
|
117
|
+
#remove any cookbooks managed by berkshelf
|
118
|
+
cookbooks.delete_if {|x| berkshelf_cookbooks.keys.member?(x.keys[0])}
|
128
119
|
end
|
129
120
|
end
|
130
121
|
end
|
data/lib/spiceweasel/nodes.rb
CHANGED
@@ -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.
|
@@ -19,13 +19,16 @@
|
|
19
19
|
module Spiceweasel
|
20
20
|
class Nodes
|
21
21
|
|
22
|
-
|
22
|
+
include CommandHelper
|
23
|
+
|
24
|
+
PROVIDERS = %w{bluebox clodo cs ec2 gandi hp lxc openstack rackspace slicehost terremark voxel vagrant}
|
23
25
|
|
24
26
|
attr_reader :create, :delete
|
25
27
|
|
26
28
|
def initialize(nodes, cookbooks, environments, roles)
|
27
29
|
@create = Array.new
|
28
30
|
@delete = Array.new
|
31
|
+
bulk_delete = false
|
29
32
|
if nodes
|
30
33
|
Spiceweasel::Log.debug("nodes: #{nodes}")
|
31
34
|
nodes.each do |node|
|
@@ -40,6 +43,13 @@ module Spiceweasel
|
|
40
43
|
options = node[name]['options'] || ''
|
41
44
|
Spiceweasel::Log.debug("node: '#{name}' options: '#{options}'")
|
42
45
|
validateOptions(name, options, environments) unless Spiceweasel::Config[:novalidation]
|
46
|
+
create_command_options = {}
|
47
|
+
%w(allow_create_failure timeout).each do |key|
|
48
|
+
if(node[name].has_key?(key))
|
49
|
+
create_command_options[key] = node[name][key]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
additional_commands = node[name]['additional_commands'] || []
|
43
53
|
end
|
44
54
|
#provider support
|
45
55
|
provider = name.split()
|
@@ -48,43 +58,60 @@ module Spiceweasel
|
|
48
58
|
if provider.length == 2
|
49
59
|
count = provider[1]
|
50
60
|
end
|
61
|
+
provided_names = []
|
51
62
|
if Spiceweasel::Config[:parallel]
|
52
63
|
parallel = "seq #{count} | parallel -j 0 -v \""
|
53
64
|
parallel += "knife #{provider[0]}#{Spiceweasel::Config[:knife_options]} server create #{options}".gsub(/\{\{n\}\}/, '{}')
|
54
65
|
parallel += " -r '#{run_list}'" unless run_list.empty?
|
55
66
|
parallel += "\""
|
56
|
-
|
67
|
+
create_command(parallel, create_command_options)
|
57
68
|
else
|
58
69
|
count.to_i.times do |i|
|
59
70
|
server = "knife #{provider[0]}#{Spiceweasel::Config[:knife_options]} server create #{options}".gsub(/\{\{n\}\}/, (i + 1).to_s)
|
60
71
|
server += " -r '#{run_list}'" unless run_list.empty?
|
61
|
-
|
72
|
+
provided_names << node[name]['name'].gsub('{{n}}', (i + 1).to_s) if node[name]['name']
|
73
|
+
create_command(server, create_command_options)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
if provided_names.empty? && provider[0] != 'windows'
|
77
|
+
bulk_delete = true
|
78
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} list | xargs knife #{provider[0]} server delete -y")
|
79
|
+
else
|
80
|
+
provided_names.each do |p_name|
|
81
|
+
delete_command("knife #{provider[0]} server delete -y #{p_name}")
|
82
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} delete #{p_name} -y")
|
83
|
+
delete_command("knife client#{Spiceweasel::Config[:knife_options]} delete #{p_name} -y")
|
62
84
|
end
|
63
85
|
end
|
64
|
-
@delete.push("knife node#{Spiceweasel::Config[:knife_options]} list | xargs knife #{provider[0]} server delete -y")
|
65
86
|
elsif name.start_with?("windows") #windows node bootstrap support
|
66
87
|
nodeline = name.split()
|
67
88
|
provider = nodeline.shift.split('_') #split on 'windows_ssh' etc
|
68
89
|
nodeline.each do |server|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
90
|
+
servercommand = "knife bootstrap #{provider[0]} #{provider[1]}#{Spiceweasel::Config[:knife_options]} #{server} #{options}"
|
91
|
+
servercommand += " -r '#{run_list}'" unless run_list.empty?
|
92
|
+
create_command(servercommand, create_command_options)
|
93
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} delete #{server} -y")
|
94
|
+
delete_command("knife client#{Spiceweasel::Config[:knife_options]} delete #{server} -y")
|
74
95
|
end
|
75
|
-
@delete.push("knife node#{Spiceweasel::Config[:knife_options]} list | xargs knife #{provider[0]} server delete -y")
|
76
96
|
else #node bootstrap support
|
77
97
|
name.split.each_with_index do |server, i|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
98
|
+
servercommand = "knife bootstrap#{Spiceweasel::Config[:knife_options]} #{server} #{options}".gsub(/\{\{n\}\}/, (i + 1).to_s)
|
99
|
+
servercommand += " -r '#{run_list}'" unless run_list.empty?
|
100
|
+
create_command(servercommand, create_command_options)
|
101
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} delete #{server} -y")
|
102
|
+
delete_command("knife client#{Spiceweasel::Config[:knife_options]} delete #{server} -y")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
unless additional_commands.empty?
|
106
|
+
additional_commands.each do |cmd|
|
107
|
+
create_command(cmd, create_command_options)
|
83
108
|
end
|
84
109
|
end
|
85
110
|
end
|
86
111
|
end
|
87
|
-
|
112
|
+
if bulk_delete
|
113
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} bulk delete .* -y")
|
114
|
+
end
|
88
115
|
end
|
89
116
|
|
90
117
|
#ensure run_list contents are listed previously.
|
data/lib/spiceweasel/roles.rb
CHANGED
@@ -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.
|
@@ -17,10 +17,13 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require 'json'
|
20
|
+
require 'chef'
|
20
21
|
|
21
22
|
module Spiceweasel
|
22
23
|
class Roles
|
23
24
|
|
25
|
+
include CommandHelper
|
26
|
+
|
24
27
|
attr_reader :role_list, :create, :delete
|
25
28
|
|
26
29
|
def initialize(roles = {}, environments = [], cookbooks = {})
|
@@ -30,6 +33,7 @@ module Spiceweasel
|
|
30
33
|
if roles
|
31
34
|
Spiceweasel::Log.debug("roles: #{roles}")
|
32
35
|
flatroles = roles.collect {|x| x.keys}.flatten
|
36
|
+
rolefiles = []
|
33
37
|
flatroles.each do |role|
|
34
38
|
Spiceweasel::Log.debug("role: #{role}")
|
35
39
|
if File.directory?("roles")
|
@@ -39,81 +43,51 @@ module Spiceweasel
|
|
39
43
|
exit(-1)
|
40
44
|
end
|
41
45
|
if File.exists?("roles/#{role}.json")
|
42
|
-
|
46
|
+
rolefiles.push("#{role}.json")
|
43
47
|
else #assume no .json means they want .rb and catchall for misssing dir
|
44
|
-
|
48
|
+
rolefiles.push("#{role}.rb")
|
45
49
|
end
|
46
|
-
|
50
|
+
delete_command("knife role#{Spiceweasel::Config[:knife_options]} delete #{role} -y")
|
47
51
|
@role_list.push(role)
|
48
52
|
end
|
53
|
+
create_command("knife role#{Spiceweasel::Config[:knife_options]} from file #{rolefiles.join(' ')}")
|
49
54
|
end
|
50
55
|
end
|
51
56
|
|
52
57
|
#validate the content of the role file
|
53
58
|
def validate(role, environments, cookbooks, roles)
|
54
59
|
#validate the role passed in match the name of either the .rb or .json
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
exit(-1)
|
60
|
+
file = %W(roles/#{role}.rb roles/#{role}.json).detect{|f| File.exists?(f)}
|
61
|
+
if(file)
|
62
|
+
if(Chef::Version.new(Chef::VERSION) < Chef::Version.new('11.0.0'))
|
63
|
+
c_role = Chef::Role.new(true)
|
64
|
+
else
|
65
|
+
c_role = Chef::Role.new
|
62
66
|
end
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
line.strip.split(',').each do |rl|
|
68
|
-
if rl =~ /recipe\[/ #it's a cookbook
|
69
|
-
#split on the brackets and any colons
|
70
|
-
dep = rl.split(/\[|\]/)[1].split(':')[0]
|
71
|
-
Spiceweasel::Log.debug("role: '#{role}' cookbook: '#{rl}': dep: '#{dep}'")
|
72
|
-
if !cookbooks.member?(dep)
|
73
|
-
STDERR.puts "ERROR: Cookbook dependency '#{dep}' from role '#{role}' is missing from the list of cookbooks in the manifest."
|
74
|
-
exit(-1)
|
75
|
-
end
|
76
|
-
elsif rl =~ /role\[/ #it's a role
|
77
|
-
#split on the brackets
|
78
|
-
dep = rl.split(/\[|\]/)[1]
|
79
|
-
Spiceweasel::Log.debug("role: '#{role}' role: '#{rl}': dep: '#{dep}'")
|
80
|
-
if !roles.member?(dep)
|
81
|
-
STDERR.puts "ERROR: Role dependency '#{dep}' from role '#{role}' is missing from the list of roles in the manifest."
|
82
|
-
exit(-1)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
#TODO validate any environment-specific runlists
|
88
|
-
elsif File.exists?("roles/#{role}.json")
|
89
|
-
#load the json, don't symbolize since we don't need json_class
|
90
|
-
f = File.read("roles/#{role}.json")
|
91
|
-
JSON.create_id = nil
|
92
|
-
rolefile = JSON.parse(f, {:symbolize_names => false})
|
93
|
-
#validate that the name inside the file matches
|
94
|
-
Spiceweasel::Log.debug("role: '#{role}' name: '#{rolefile['name']}'")
|
95
|
-
if !role.eql?(rolefile['name'])
|
96
|
-
STDERR.puts "ERROR: Role '#{role}' listed in the manifest does not match the name '#{rolefile['name']}' within the 'roles/#{role}.json' file."
|
67
|
+
c_role.from_file(file)
|
68
|
+
Spiceweasel::Log.debug("role: '#{role}' name: '#{c_role.name}'")
|
69
|
+
if !role.eql?(c_role.name)
|
70
|
+
STDERR.puts "ERROR: Role '#{role}' listed in the manifest does not match the name '#{c_role.name}' within the roles/#{role}.rb file."
|
97
71
|
exit(-1)
|
98
72
|
end
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
STDERR.puts "ERROR: Cookbook dependency '#{dep}' from role '#{role}' is missing from the list of cookbooks in the manifest."
|
73
|
+
c_role.run_list.each do |runlist_item|
|
74
|
+
if(runlist_item.recipe?)
|
75
|
+
Spiceweasel::Log.debug("recipe: #{runlist_item.name}")
|
76
|
+
cookbook,recipe = runlist_item.name.split('::')
|
77
|
+
Spiceweasel::Log.debug("role: '#{role}' cookbook: '#{cookbook}' dep: '#{runlist_item}'")
|
78
|
+
unless(cookbooks.member?(cookbook))
|
79
|
+
STDERR.puts "ERROR: Cookbook dependency '#{runlist_item}' from role '#{role}' is missing from the list of cookbooks in the manifest."
|
107
80
|
exit(-1)
|
108
81
|
end
|
109
|
-
elsif
|
110
|
-
#
|
111
|
-
|
112
|
-
|
113
|
-
if !roles.member?(dep)
|
114
|
-
STDERR.puts "ERROR: Role dependency '#{dep}' from role '#{role}' is missing from the list of roles in the manifest."
|
82
|
+
elsif(runlist_item.role?)
|
83
|
+
Spiceweasel::Log.debug("role: '#{role}' role: '#{runlist_item}': dep: '#{runlist_item.name}'")
|
84
|
+
unless(roles.member?(runlist_item.name))
|
85
|
+
STDERR.puts "ERROR: Role dependency '#{runlist_item.name}' from role '#{role}' is missing from the list of roles in the manifest."
|
115
86
|
exit(-1)
|
116
87
|
end
|
88
|
+
else
|
89
|
+
STDERR.puts "ERROR: Unknown item in runlist: #{runlist_item.name}"
|
90
|
+
exit(-1)
|
117
91
|
end
|
118
92
|
end
|
119
93
|
#TODO validate any environment-specific runlists
|
data/lib/spiceweasel/version.rb
CHANGED
@@ -5,6 +5,7 @@ describe 'The Spiceweasel binary' do
|
|
5
5
|
knife cookbook delete apache2 -a -y
|
6
6
|
knife cookbook delete apt 1.2.0 -a -y
|
7
7
|
knife cookbook delete mysql -a -y
|
8
|
+
knife cookbook delete ntp -a -y
|
8
9
|
knife environment delete development -y
|
9
10
|
knife environment delete qa -y
|
10
11
|
knife environment delete production -y
|
@@ -15,43 +16,34 @@ knife role delete webserver -y
|
|
15
16
|
knife data bag delete users -y
|
16
17
|
knife data bag delete data -y
|
17
18
|
knife data bag delete passwords -y
|
18
|
-
knife node delete
|
19
|
-
knife client delete
|
20
|
-
knife node delete
|
21
|
-
knife client delete
|
22
|
-
knife node delete
|
23
|
-
knife client delete
|
19
|
+
knife node delete serverA -y
|
20
|
+
knife client delete serverA -y
|
21
|
+
knife node delete serverB -y
|
22
|
+
knife client delete serverB -y
|
23
|
+
knife node delete serverC -y
|
24
|
+
knife client delete serverC -y
|
24
25
|
knife node list | xargs knife rackspace server delete -y
|
25
|
-
knife node delete
|
26
|
-
knife client delete
|
27
|
-
knife node
|
28
|
-
knife
|
29
|
-
knife
|
30
|
-
knife
|
31
|
-
knife client delete knife bootstrap windows ssh winboxC -x Administrator -P 'super_secret_password' -r 'role[base],role[iisserver]' -y
|
32
|
-
knife node list | xargs knife windows server delete -y
|
26
|
+
knife node delete winboxA -y
|
27
|
+
knife client delete winboxA -y
|
28
|
+
knife node delete winboxB -y
|
29
|
+
knife client delete winboxB -y
|
30
|
+
knife node delete winboxC -y
|
31
|
+
knife client delete winboxC -y
|
33
32
|
knife node bulk delete .* -y
|
34
33
|
knife node list | xargs knife ec2 server delete -y
|
35
34
|
knife node list | xargs knife ec2 server delete -y
|
36
35
|
knife node bulk delete .* -y
|
37
36
|
knife cookbook upload apache2
|
38
37
|
knife cookbook upload apt --freeze
|
39
|
-
knife cookbook upload mysql
|
40
|
-
knife environment from file development.rb
|
41
|
-
knife
|
42
|
-
knife environment from file production.rb
|
43
|
-
knife role from file base.rb
|
44
|
-
knife role from file iisserver.rb
|
45
|
-
knife role from file monitoring.rb
|
46
|
-
knife role from file webserver.rb
|
38
|
+
knife cookbook upload mysql ntp
|
39
|
+
knife environment from file development.rb qa.rb production.rb
|
40
|
+
knife role from file base.rb iisserver.rb monitoring.rb webserver.rb
|
47
41
|
knife data bag create users
|
48
|
-
knife data bag from file users alice.json
|
49
|
-
knife data bag from file users bob.json
|
50
|
-
knife data bag from file users chuck.json
|
42
|
+
knife data bag from file users alice.json bob.json chuck.json
|
51
43
|
knife data bag create data
|
44
|
+
knife data bag from file data *.json
|
52
45
|
knife data bag create passwords
|
53
|
-
knife data bag from file passwords mysql.json --secret-file secret_key
|
54
|
-
knife data bag from file passwords rabbitmq.json --secret-file secret_key
|
46
|
+
knife data bag from file passwords mysql.json rabbitmq.json --secret-file secret_key
|
55
47
|
knife bootstrap serverA -i ~/.ssh/mray.pem -x user --sudo -r 'role[base]'
|
56
48
|
knife bootstrap serverB -i ~/.ssh/mray.pem -x user --sudo -E production -r 'role[base]'
|
57
49
|
knife bootstrap serverC -i ~/.ssh/mray.pem -x user --sudo -E production -r 'role[base]'
|
@@ -70,7 +62,15 @@ knife ec2 server create -S mray -i ~/.ssh/mray.pem -x ubuntu -G default -I ami-7
|
|
70
62
|
@spiceweasel_binary = File.join(File.dirname(__FILE__), *%w[.. .. bin spiceweasel])
|
71
63
|
end
|
72
64
|
|
73
|
-
it "maintains consistent output from the example config" do
|
65
|
+
it "maintains consistent output from the example config with yml" do
|
74
66
|
`#{@spiceweasel_binary} -r --novalidation examples/example.yml`.should == @expected_output
|
75
67
|
end
|
68
|
+
|
69
|
+
it "maintains consistent output from the example config with json" do
|
70
|
+
`#{@spiceweasel_binary} -r --novalidation examples/example.json`.should == @expected_output
|
71
|
+
end
|
72
|
+
|
73
|
+
it "maintains consistent output from the example config with rb" do
|
74
|
+
`#{@spiceweasel_binary} -r --novalidation examples/example.rb`.should == @expected_output
|
75
|
+
end
|
76
76
|
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: 2.0
|
4
|
+
version: 2.1.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-03-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -107,6 +107,38 @@ dependencies:
|
|
107
107
|
- - ! '>='
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: berkshelf
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: solve
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :runtime
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
110
142
|
- !ruby/object:Gem::Dependency
|
111
143
|
name: rspec
|
112
144
|
requirement: !ruby/object:Gem::Requirement
|
@@ -135,8 +167,11 @@ files:
|
|
135
167
|
- LICENSE
|
136
168
|
- README.md
|
137
169
|
- bin/spiceweasel
|
170
|
+
- lib/spiceweasel/berksfile.rb
|
138
171
|
- lib/spiceweasel/cli.rb
|
139
172
|
- lib/spiceweasel/clusters.rb
|
173
|
+
- lib/spiceweasel/command.rb
|
174
|
+
- lib/spiceweasel/command_helper.rb
|
140
175
|
- lib/spiceweasel/config.rb
|
141
176
|
- lib/spiceweasel/cookbooks.rb
|
142
177
|
- lib/spiceweasel/data_bags.rb
|