spiceweasel 2.6.0 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +6 -14
- data/README.md +33 -9
- data/bin/spiceweasel +3 -3
- data/lib/spiceweasel.rb +3 -2
- data/lib/spiceweasel/berksfile.rb +6 -10
- data/lib/spiceweasel/cli.rb +174 -129
- data/lib/spiceweasel/clusters.rb +31 -23
- data/lib/spiceweasel/command.rb +23 -5
- data/lib/spiceweasel/command_helper.rb +36 -2
- data/lib/spiceweasel/config.rb +4 -3
- data/lib/spiceweasel/cookbooks.rb +76 -57
- data/lib/spiceweasel/data_bags.rb +100 -64
- data/lib/spiceweasel/environments.rb +78 -56
- data/lib/spiceweasel/execute.rb +6 -7
- data/lib/spiceweasel/extract_local.rb +59 -46
- data/lib/spiceweasel/knife.rb +21 -20
- data/lib/spiceweasel/log.rb +5 -5
- data/lib/spiceweasel/nodes.rb +261 -193
- data/lib/spiceweasel/roles.rb +107 -76
- data/lib/spiceweasel/version.rb +5 -3
- data/test/chef-repo/Berksfile +4 -0
- data/test/chef-repo/Berksfile.lock +10 -0
- data/test/chef-repo/PASSWORD +1 -0
- data/test/chef-repo/cookbooks/abc/CHANGELOG.md +13 -0
- data/test/chef-repo/cookbooks/abc/README.md +68 -0
- data/test/chef-repo/cookbooks/abc/metadata.rb +7 -0
- data/test/chef-repo/cookbooks/abc/recipes/default.rb +8 -0
- data/test/chef-repo/cookbooks/def/CHANGELOG.md +13 -0
- data/test/chef-repo/cookbooks/def/README.md +68 -0
- data/test/chef-repo/cookbooks/def/metadata.rb +7 -0
- data/test/chef-repo/cookbooks/def/recipes/default.rb +8 -0
- data/test/chef-repo/cookbooks/fail1/README.md +68 -0
- data/test/chef-repo/cookbooks/fail1/metadata.rb +9 -0
- data/test/chef-repo/cookbooks/fail2/README.md +68 -0
- data/test/chef-repo/cookbooks/fail2/metadata.rb +9 -0
- data/test/chef-repo/cookbooks/fail3/README.md +68 -0
- data/test/chef-repo/cookbooks/fail3/metadata.rb +9 -0
- data/test/chef-repo/cookbooks/ghi/CHANGELOG.md +13 -0
- data/test/chef-repo/cookbooks/ghi/README.md +68 -0
- data/test/chef-repo/cookbooks/ghi/metadata.rb +7 -0
- data/test/chef-repo/cookbooks/ghi/recipes/default.rb +8 -0
- data/test/chef-repo/cookbooks/jkl/CHANGELOG.md +13 -0
- data/test/chef-repo/cookbooks/jkl/README.md +68 -0
- data/test/chef-repo/cookbooks/jkl/metadata.rb +10 -0
- data/test/chef-repo/cookbooks/jkl/recipes/default.rb +8 -0
- data/test/chef-repo/cookbooks/mno/CHANGELOG.md +13 -0
- data/test/chef-repo/cookbooks/mno/README.md +68 -0
- data/test/chef-repo/cookbooks/mno/metadata.rb +9 -0
- data/test/chef-repo/cookbooks/mno/recipes/default.rb +8 -0
- data/test/chef-repo/data_bags/junk/README +1 -0
- data/test/chef-repo/data_bags/junk/abc.json +4 -0
- data/test/chef-repo/data_bags/junk/ade.json +4 -0
- data/test/chef-repo/data_bags/junk/afg.json +4 -0
- data/test/chef-repo/data_bags/junk/bcd.json +4 -0
- data/test/chef-repo/data_bags/junk/sub1/cde1.json +4 -0
- data/test/chef-repo/data_bags/junk/sub1/cde2.json +4 -0
- data/test/chef-repo/data_bags/junk/sub2/def1.json +4 -0
- data/test/chef-repo/data_bags/junk/sub2/def2.json +4 -0
- data/test/chef-repo/data_bags/users/README +1 -0
- data/test/chef-repo/data_bags/users/badjson.json +8 -0
- data/test/chef-repo/data_bags/users/failname.json +8 -0
- data/test/chef-repo/data_bags/users/mray.json +8 -0
- data/test/chef-repo/data_bags/users/ubuntu.json +8 -0
- data/test/chef-repo/environments/development.rb +2 -0
- data/test/chef-repo/environments/fail2.rb +8 -0
- data/test/chef-repo/environments/fail3.rb +2 -0
- data/test/chef-repo/environments/production-blue.json +177 -0
- data/test/chef-repo/environments/production-green.json +177 -0
- data/test/chef-repo/environments/production-red.json +177 -0
- data/test/chef-repo/environments/qa.rb +2 -0
- data/test/chef-repo/environments/sub/efg1.rb +2 -0
- data/test/chef-repo/environments/sub/efg2.json +177 -0
- data/test/chef-repo/fail-cookbook1.yml +19 -0
- data/test/chef-repo/fail-cookbook2.yml +21 -0
- data/test/chef-repo/fail-cookbook3.yml +37 -0
- data/test/chef-repo/fail-cookbook4.yml +37 -0
- data/test/chef-repo/fail-cookbook5.yml +10 -0
- data/test/chef-repo/fail-cookbook6.yml +9 -0
- data/test/chef-repo/fail-db1.yml +12 -0
- data/test/chef-repo/fail-db2.yml +10 -0
- data/test/chef-repo/fail-db3.yml +10 -0
- data/test/chef-repo/fail-db4.yml +10 -0
- data/test/chef-repo/fail-env1.yml +27 -0
- data/test/chef-repo/fail-env2.yml +27 -0
- data/test/chef-repo/fail-env3.yml +28 -0
- data/test/chef-repo/fail-env4.yml +28 -0
- data/test/chef-repo/fail-roles1.yml +22 -0
- data/test/chef-repo/fail-roles2.yml +21 -0
- data/test/chef-repo/fail-roles3.yml +23 -0
- data/test/chef-repo/fail-roles4.yml +23 -0
- data/test/chef-repo/fail-roles5.yml +23 -0
- data/test/chef-repo/infrastructure.yml +43 -0
- data/test/chef-repo/nodes/boxy.lab.atx.json +1756 -0
- data/test/chef-repo/nodes/guenter.home.atx.json +2503 -0
- data/test/chef-repo/roles/README +1 -0
- data/test/chef-repo/roles/base.rb +18 -0
- data/test/chef-repo/roles/base2.rb +16 -0
- data/test/chef-repo/roles/base3.rb +17 -0
- data/test/chef-repo/roles/base4.rb +15 -0
- data/test/chef-repo/roles/fail1.rb +8 -0
- data/test/chef-repo/roles/fail2.rb +5 -0
- data/test/chef-repo/roles/fail3.rb +5 -0
- data/test/chef-repo/roles/sub/bw2.json +21 -0
- data/test/chef-repo/roles/sub/bwi1.json +20 -0
- data/test/chef-repo/roles/tc.rb +13 -0
- data/test/examples/cluster-file-example.yml +14 -0
- data/test/examples/example-cluster.yml +8 -0
- data/test/examples/example.json +127 -0
- data/test/examples/example.rb +128 -0
- data/test/examples/example.yml +67 -0
- data/test/examples/google-example.yml +33 -0
- data/test/examples/joyent-vsphere-example.yml +15 -0
- data/test/examples/knife.yml +7 -0
- data/test/examples/kvm-example.yml +22 -0
- data/test/examples/node-example.yml +23 -0
- data/test/examples/php-quick-start.yml +83 -0
- data/test/extract-repo/Berksfile +4 -0
- data/test/extract-repo/Berksfile.lock +10 -0
- data/test/extract-repo/cookbooks/abc/CHANGELOG.md +13 -0
- data/test/extract-repo/cookbooks/abc/README.md +68 -0
- data/test/extract-repo/cookbooks/abc/metadata.rb +7 -0
- data/test/extract-repo/cookbooks/abc/recipes/default.rb +8 -0
- data/test/extract-repo/cookbooks/def/CHANGELOG.md +13 -0
- data/test/extract-repo/cookbooks/def/README.md +68 -0
- data/test/extract-repo/cookbooks/def/metadata.rb +7 -0
- data/test/extract-repo/cookbooks/def/recipes/default.rb +8 -0
- data/test/extract-repo/cookbooks/ghi/CHANGELOG.md +13 -0
- data/test/extract-repo/cookbooks/ghi/README.md +68 -0
- data/test/extract-repo/cookbooks/ghi/metadata.rb +7 -0
- data/test/extract-repo/cookbooks/ghi/recipes/default.rb +8 -0
- data/test/extract-repo/cookbooks/jkl/CHANGELOG.md +13 -0
- data/test/extract-repo/cookbooks/jkl/README.md +68 -0
- data/test/extract-repo/cookbooks/jkl/metadata.rb +10 -0
- data/test/extract-repo/cookbooks/jkl/recipes/default.rb +8 -0
- data/test/extract-repo/cookbooks/mno/CHANGELOG.md +13 -0
- data/test/extract-repo/cookbooks/mno/README.md +68 -0
- data/test/extract-repo/cookbooks/mno/metadata.rb +9 -0
- data/test/extract-repo/cookbooks/mno/recipes/default.rb +8 -0
- data/test/extract-repo/data_bags/junk/README +1 -0
- data/test/extract-repo/data_bags/junk/abc.json +4 -0
- data/test/extract-repo/data_bags/junk/ade.json +4 -0
- data/test/extract-repo/data_bags/junk/afg.json +4 -0
- data/test/extract-repo/data_bags/junk/bcd.json +4 -0
- data/test/extract-repo/data_bags/junk/sub1/cde1.json +4 -0
- data/test/extract-repo/data_bags/junk/sub1/cde2.json +4 -0
- data/test/extract-repo/data_bags/junk/sub2/def1.json +4 -0
- data/test/extract-repo/data_bags/junk/sub2/def2.json +4 -0
- data/test/extract-repo/data_bags/users/README +1 -0
- data/test/extract-repo/data_bags/users/mray.json +8 -0
- data/test/extract-repo/data_bags/users/ubuntu.json +8 -0
- data/test/extract-repo/environments/development.rb +2 -0
- data/test/extract-repo/environments/production-blue.json +177 -0
- data/test/extract-repo/environments/production-green.json +177 -0
- data/test/extract-repo/environments/production-red.json +177 -0
- data/test/extract-repo/environments/qa.rb +2 -0
- data/test/extract-repo/environments/sub/efg1.rb +2 -0
- data/test/extract-repo/environments/sub/efg2.json +177 -0
- data/test/extract-repo/nodes/boxy.lab.atx.json +1756 -0
- data/test/extract-repo/nodes/guenter.home.atx.json +2503 -0
- data/test/extract-repo/roles/README +1 -0
- data/test/extract-repo/roles/base.rb +18 -0
- data/test/extract-repo/roles/base2.rb +16 -0
- data/test/extract-repo/roles/base3.rb +17 -0
- data/test/extract-repo/roles/base4.rb +16 -0
- data/test/extract-repo/roles/sub/bw2.json +21 -0
- data/test/extract-repo/roles/sub/bwi1.json +20 -0
- data/test/extract-repo/roles/tc.rb +13 -0
- data/test/extract-repo2/cookbooks/README.md +1 -0
- data/test/extract-repo2/data_bags/README.md +1 -0
- data/test/extract-repo2/environments/README.md +1 -0
- data/test/extract-repo2/nodes/README.md +1 -0
- data/test/extract-repo2/roles/README.md +1 -0
- metadata +357 -67
- data/spec/bin/chef_client_spec.rb +0 -72
- data/spec/bin/google_spec.rb +0 -105
- data/spec/bin/joyent-vsphere_spec.rb +0 -25
- data/spec/bin/knife_spec.rb +0 -18
- data/spec/bin/kvm_spec.rb +0 -29
- data/spec/bin/node_spec.rb +0 -108
- data/spec/bin/spiceweasel_spec.rb +0 -136
data/lib/spiceweasel/nodes.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
#
|
2
|
-
# Author:: Matt Ray (<matt@
|
3
|
+
# Author:: Matt Ray (<matt@getchef.com>)
|
3
4
|
#
|
4
|
-
# Copyright:: 2011-
|
5
|
+
# Copyright:: 2011-2014, Chef Software, Inc <legal@getchef.com>
|
5
6
|
#
|
6
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
8
|
# you may not use this file except in compliance with the License.
|
@@ -17,97 +18,98 @@
|
|
17
18
|
#
|
18
19
|
|
19
20
|
module Spiceweasel
|
21
|
+
# manages parsing of Nodes
|
20
22
|
class Nodes
|
21
|
-
|
22
23
|
include CommandHelper
|
23
24
|
|
24
|
-
PROVIDERS = %w
|
25
|
+
PROVIDERS = %w(bluebox clodo cs digital_ocean ec2 gandi google hp joyent kvm linode lxc openstack rackspace vagrant vcair vsphere)
|
25
26
|
|
26
27
|
attr_reader :create, :delete
|
27
28
|
|
28
|
-
def initialize(nodes, cookbooks, environments, roles, knifecommands)
|
29
|
-
@create =
|
30
|
-
@delete =
|
31
|
-
chefclient =
|
29
|
+
def initialize(nodes, cookbooks, environments, roles, knifecommands, rootoptions) # rubocop:disable CyclomaticComplexity
|
30
|
+
@create = []
|
31
|
+
@delete = []
|
32
|
+
chefclient = []
|
32
33
|
create_command_options = {}
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
34
|
+
|
35
|
+
return unless nodes
|
36
|
+
|
37
|
+
Spiceweasel::Log.debug("nodes: #{nodes}")
|
38
|
+
nodes.each do |node|
|
39
|
+
name = node.keys.first
|
40
|
+
names = name.split
|
41
|
+
Spiceweasel::Log.debug("node: '#{name}' '#{node[name]}'")
|
42
|
+
# get the node's run_list and options
|
43
|
+
if node[name]
|
44
|
+
run_list = process_run_list(node[name]['run_list'])
|
45
|
+
Spiceweasel::Log.debug("node: '#{name}' run_list: '#{run_list}'")
|
46
|
+
validate_run_list(name, run_list, cookbooks, roles) unless Spiceweasel::Config[:novalidation]
|
47
|
+
options = ((node[name]['options'] || '') + ' ' + (rootoptions || '')).rstrip
|
48
|
+
Spiceweasel::Log.debug("node: '#{name}' options: '#{options}'")
|
49
|
+
validate_options(name, options, environments) unless Spiceweasel::Config[:novalidation]
|
50
|
+
%w(allow_create_failure timeout).each do |key|
|
51
|
+
if node[name].key?(key)
|
52
|
+
create_command_options[key] = node[name][key]
|
51
53
|
end
|
52
|
-
additional_commands = node[name]['additional_commands'] || []
|
53
54
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
55
|
+
additional_commands = node[name]['additional_commands'] || []
|
56
|
+
end
|
57
|
+
if Spiceweasel::Config[:chefclient]
|
58
|
+
chefclient.push(process_chef_client(names, options, run_list))
|
59
|
+
elsif Spiceweasel::Config[:node_only]
|
60
|
+
process_nodes_only(names, options, run_list, create_command_options)
|
61
|
+
else # create/delete
|
62
|
+
# provider support
|
63
|
+
if PROVIDERS.member?(names[0])
|
64
|
+
count = names.length == 2 ? names[1] : 1
|
65
|
+
process_providers(names, count, node[name]['name'], options, run_list, create_command_options, knifecommands)
|
66
|
+
elsif names[0].start_with?('windows_')
|
67
|
+
# windows node bootstrap support
|
68
|
+
protocol = names.shift.split('_') # split on 'windows_ssh' etc
|
69
|
+
names.each do |server|
|
70
|
+
servercommand = "knife bootstrap #{protocol[0]} #{protocol[1]}#{Spiceweasel::Config[:knife_options]} #{server} #{options}"
|
71
|
+
servercommand += " -r '#{run_list}'" unless run_list.empty?
|
72
|
+
create_command(servercommand, create_command_options)
|
73
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} delete #{server} -y")
|
74
|
+
delete_command("knife client#{Spiceweasel::Config[:knife_options]} delete #{server} -y")
|
75
|
+
end
|
76
|
+
else
|
77
|
+
# node bootstrap support
|
78
|
+
name.split.each_with_index do |server, i|
|
79
|
+
servercommand = node_numerate("knife bootstrap#{Spiceweasel::Config[:knife_options]} #{server} #{options}", i + 1, count)
|
80
|
+
servercommand += " -r '#{run_list}'" unless run_list.empty?
|
81
|
+
create_command(servercommand, create_command_options)
|
82
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} delete #{server} -y")
|
83
|
+
delete_command("knife client#{Spiceweasel::Config[:knife_options]} delete #{server} -y")
|
82
84
|
end
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
85
|
+
end
|
86
|
+
unless additional_commands.empty?
|
87
|
+
additional_commands.each do |cmd|
|
88
|
+
create_command(cmd, create_command_options)
|
87
89
|
end
|
88
90
|
end
|
89
91
|
end
|
90
|
-
if Spiceweasel::Config[:bulkdelete]
|
91
|
-
delete_command("knife node#{Spiceweasel::Config[:knife_options]} bulk delete .* -y")
|
92
|
-
end
|
93
|
-
#remove repeats in chefclient and push into create_command
|
94
|
-
chefclient.flatten.each_with_index {|x,i| create_command(x, create_command_options) unless x.eql?(chefclient[i-1])} if Spiceweasel::Config[:chefclient]
|
95
|
-
#nodeonly
|
96
92
|
end
|
93
|
+
if Spiceweasel::Config[:bulkdelete]
|
94
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} bulk delete .* -y")
|
95
|
+
end
|
96
|
+
# remove repeats in chefclient and push into create_command
|
97
|
+
chefclient.flatten.each_with_index { |x, i| create_command(x, create_command_options) unless x.eql?(chefclient[i - 1]) } if Spiceweasel::Config[:chefclient]
|
98
|
+
# nodeonly
|
97
99
|
end
|
98
100
|
|
99
|
-
#ensure run_list contents are listed previously.
|
101
|
+
# ensure run_list contents are listed previously.
|
100
102
|
def validate_run_list(node, run_list, cookbooks, roles)
|
101
103
|
run_list.split(',').each do |item|
|
102
|
-
if item.start_with?(
|
103
|
-
#recipe[foo] or recipe[foo::bar]
|
104
|
+
if item.start_with?('recipe[')
|
105
|
+
# recipe[foo] or recipe[foo::bar]
|
104
106
|
cb = item.split(/\[|\]/)[1].split(':')[0]
|
105
107
|
unless cookbooks.member?(cb)
|
106
108
|
STDERR.puts "ERROR: '#{node}' run list cookbook '#{cb}' is missing from the list of cookbooks in the manifest."
|
107
109
|
exit(-1)
|
108
110
|
end
|
109
|
-
elsif item.start_with?(
|
110
|
-
#role[blah]
|
111
|
+
elsif item.start_with?('role[')
|
112
|
+
# role[blah]
|
111
113
|
role = item.split(/\[|\]/)[1]
|
112
114
|
unless roles.member?(role)
|
113
115
|
STDERR.puts "ERROR: '#{node}' run list role '#{role}' is missing from the list of roles in the manifest."
|
@@ -120,10 +122,10 @@ module Spiceweasel
|
|
120
122
|
end
|
121
123
|
end
|
122
124
|
|
123
|
-
#for now, just check that -E is legit
|
125
|
+
# for now, just check that -E is legit
|
124
126
|
def validate_options(node, options, environments)
|
125
|
-
if options =~ /-E/ #check for environments
|
126
|
-
env = options.split('-E')[1].split
|
127
|
+
if options =~ /-E/ # check for environments
|
128
|
+
env = options.split('-E')[1].split[0]
|
127
129
|
unless environments.member?(env)
|
128
130
|
STDERR.puts "ERROR: '#{node}' environment '#{env}' is missing from the list of environments in the manifest."
|
129
131
|
exit(-1)
|
@@ -132,153 +134,213 @@ module Spiceweasel
|
|
132
134
|
end
|
133
135
|
|
134
136
|
# handle --nodes-only
|
135
|
-
def process_nodes_only(names, options, run_list, create_command_options)
|
137
|
+
def process_nodes_only(names, options, run_list, create_command_options) # rubocop:disable CyclomaticComplexity
|
136
138
|
nodenames = []
|
137
139
|
if PROVIDERS.member?(names[0])
|
138
140
|
count = names.length == 2 ? names[1] : 1
|
139
|
-
|
140
|
-
|
141
|
-
optname = opt.sub(/-N|--node-name/,'').lstrip
|
142
|
-
optname = options.split[options.split.find_index(opt)+1] if optname.empty?
|
143
|
-
count.to_i.times do |i|
|
144
|
-
nodenames.push(optname.gsub(/\{\{n\}\}/, (i + 1).to_s))
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
elsif names[0].start_with?("windows_")
|
141
|
+
do_provider_members(count, nodenames, options)
|
142
|
+
elsif names[0].start_with?('windows_')
|
149
143
|
nodenames.push(names[1..-1])
|
150
|
-
else #standard nodes
|
144
|
+
else # standard nodes
|
151
145
|
nodenames.push(names)
|
152
146
|
end
|
153
147
|
nodenames.flatten.each do |node|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
148
|
+
node_names_flatten(create_command_options, node, run_list)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def do_provider_members(count, nodenames, options)
|
153
|
+
options.split.each do |opt|
|
154
|
+
if opt =~ /^-N|^--node-name/
|
155
|
+
optname = opt.sub(/-N|--node-name/, '').lstrip
|
156
|
+
optname = options.split[options.split.find_index(opt) + 1] if optname.empty?
|
157
|
+
count.to_i.times do |i|
|
158
|
+
nodenames.push(node_numerate(optname, i + 1, count))
|
161
159
|
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def node_names_flatten(create_command_options, node, run_list)
|
165
|
+
if File.directory?('nodes/')
|
166
|
+
if File.exist?("nodes/#{node}.json")
|
167
|
+
validate_node_file(node) unless Spiceweasel::Config[:novalidation]
|
168
|
+
servercommand = "knife node from file #{node}.json #{Spiceweasel::Config[:knife_options]}".rstrip
|
162
169
|
else
|
163
|
-
STDERR.puts "'nodes'
|
170
|
+
STDERR.puts "'nodes/#{node}.json' not found, unable to validate or load node. Using 'knife node create' instead."
|
164
171
|
servercommand = "knife node create -d #{node} #{Spiceweasel::Config[:knife_options]}".rstrip
|
165
172
|
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
delete_command("knife client#{Spiceweasel::Config[:knife_options]} delete #{node} -y")
|
173
|
+
else
|
174
|
+
STDERR.puts "'nodes' directory not found, unable to validate or load nodes. Using 'knife node create' instead."
|
175
|
+
servercommand = "knife node create -d #{node} #{Spiceweasel::Config[:knife_options]}".rstrip
|
170
176
|
end
|
177
|
+
create_command(servercommand, create_command_options)
|
178
|
+
create_command("knife node run_list set #{node} '#{run_list}'", create_command_options) unless run_list.empty?
|
179
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} delete #{node} -y")
|
180
|
+
delete_command("knife client#{Spiceweasel::Config[:knife_options]} delete #{node} -y")
|
171
181
|
end
|
172
182
|
|
173
183
|
# validate individual node files
|
174
184
|
def validate_node_file(name)
|
175
185
|
# read in the file
|
176
186
|
node = Chef::JSONCompat.from_json(IO.read("nodes/#{name}.json"))
|
187
|
+
|
177
188
|
# check the node name vs. contents of the file
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
189
|
+
return unless node['name'] != name
|
190
|
+
|
191
|
+
STDERR.puts "ERROR: Node '#{name}' listed in the manifest does not match the name '#{node['name']}' within the nodes/#{name}.json file."
|
192
|
+
exit(-1)
|
182
193
|
end
|
183
194
|
|
184
|
-
#manage all the provider logic
|
185
|
-
def process_providers(names, count, name, options, run_list, create_command_options, knifecommands)
|
195
|
+
# manage all the provider logic
|
196
|
+
def process_providers(names, count, name, options, run_list, create_command_options, knifecommands) # rubocop:disable CyclomaticComplexity
|
186
197
|
provider = names[0]
|
187
198
|
validate_provider(provider, names, count, options, knifecommands) unless Spiceweasel::Config[:novalidation]
|
188
199
|
provided_names = []
|
189
|
-
if name.nil? && options.split.index('-N') #pull this out for deletes
|
190
|
-
name = options.split[options.split.index('-N')+1]
|
191
|
-
count.to_i.times {|i| provided_names << name
|
200
|
+
if name.nil? && options.split.index('-N') # pull this out for deletes
|
201
|
+
name = options.split[options.split.index('-N') + 1]
|
202
|
+
count.to_i.times { |i| provided_names << node_numerate(name, i + 1, count) } if name
|
192
203
|
end
|
204
|
+
|
193
205
|
# google can have names or numbers
|
194
206
|
if provider.eql?('google') && names[1].to_i == 0
|
195
|
-
names
|
196
|
-
|
197
|
-
|
198
|
-
create_command(server, create_command_options)
|
199
|
-
provided_names << gname
|
200
|
-
end
|
207
|
+
do_google_numeric_provider(create_command_options, names, options, provided_names, run_list)
|
208
|
+
elsif Spiceweasel::Config[:parallel]
|
209
|
+
process_parallel(count, create_command_options, name, options, provider, run_list)
|
201
210
|
else
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
211
|
+
determine_cloud_provider(count, create_command_options, name, options, provider, run_list)
|
212
|
+
end
|
213
|
+
if Spiceweasel::Config[:bulkdelete] && provided_names.empty?
|
214
|
+
do_bulk_delete(provider)
|
215
|
+
else
|
216
|
+
provided_names.each do |p_name|
|
217
|
+
do_provided_names(p_name, provider)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def determine_cloud_provider(count, create_command_options, name, options, provider, run_list)
|
223
|
+
count.to_i.times do |i|
|
224
|
+
if provider.eql?('vsphere')
|
225
|
+
server = node_numerate("knife #{provider}#{Spiceweasel::Config[:knife_options]} vm clone #{options}", i + 1, count)
|
226
|
+
elsif provider.eql?('kvm')
|
227
|
+
server = node_numerate("knife #{provider}#{Spiceweasel::Config[:knife_options]} vm create #{options}", i + 1, count)
|
228
|
+
elsif provider.eql?('digital_ocean')
|
229
|
+
server = node_numerate("knife #{provider}#{Spiceweasel::Config[:knife_options]} droplet create #{options}", i + 1, count)
|
230
|
+
elsif provider.eql?('google')
|
231
|
+
server = node_numerate("knife #{provider}#{Spiceweasel::Config[:knife_options]} server create #{name} #{options}", i + 1, count)
|
218
232
|
else
|
219
|
-
|
220
|
-
if provider.eql?('vsphere')
|
221
|
-
server = "knife #{provider}#{Spiceweasel::Config[:knife_options]} vm clone #{options}".gsub(/\{\{n\}\}/, (i + 1).to_s)
|
222
|
-
elsif provider.eql?('kvm')
|
223
|
-
server = "knife #{provider}#{Spiceweasel::Config[:knife_options]} vm create #{options}".gsub(/\{\{n\}\}/, (i + 1).to_s)
|
224
|
-
elsif provider.eql?('digital_ocean')
|
225
|
-
server = "knife #{provider}#{Spiceweasel::Config[:knife_options]} droplet create #{options}".gsub(/\{\{n\}\}/, (i + 1).to_s)
|
226
|
-
elsif provider.eql?('google')
|
227
|
-
server = "knife #{provider}#{Spiceweasel::Config[:knife_options]} server create #{name} #{options}".gsub(/\{\{n\}\}/, (i + 1).to_s)
|
228
|
-
else
|
229
|
-
server = "knife #{provider}#{Spiceweasel::Config[:knife_options]} server create #{options}".gsub(/\{\{n\}\}/, (i + 1).to_s)
|
230
|
-
end
|
231
|
-
server += " -r '#{run_list}'" unless run_list.empty?
|
232
|
-
create_command(server, create_command_options)
|
233
|
-
end
|
233
|
+
server = node_numerate("knife #{provider}#{Spiceweasel::Config[:knife_options]} server create #{options}", i + 1, count)
|
234
234
|
end
|
235
|
+
server += " -r '#{run_list}'" unless run_list.empty?
|
236
|
+
create_command(server, create_command_options)
|
235
237
|
end
|
236
|
-
|
237
|
-
|
238
|
+
end
|
239
|
+
|
240
|
+
def do_google_numeric_provider(create_command_options, names, options, provided_names, run_list)
|
241
|
+
names[1..-1].each do |gname|
|
242
|
+
server = "knife google#{Spiceweasel::Config[:knife_options]} server create #{gname} #{options}"
|
243
|
+
server += " -r '#{run_list}'" unless run_list.empty?
|
244
|
+
create_command(server, create_command_options)
|
245
|
+
provided_names << gname
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def do_provided_names(p_name, provider)
|
250
|
+
if ['kvm', 'vsphere'].member?(provider)
|
251
|
+
delete_command("knife #{provider} vm delete #{p_name} -y")
|
252
|
+
elsif ['digital_ocean'].member?(provider)
|
253
|
+
delete_command("knife #{provider} droplet destroy #{p_name} -y")
|
254
|
+
else
|
255
|
+
delete_command("knife #{provider} server delete #{p_name} -y")
|
256
|
+
end
|
257
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} delete #{p_name} -y")
|
258
|
+
delete_command("knife client#{Spiceweasel::Config[:knife_options]} delete #{p_name} -y")
|
259
|
+
end
|
260
|
+
|
261
|
+
def do_bulk_delete(provider)
|
262
|
+
if ['kvm', 'vsphere'].member?(provider)
|
263
|
+
if bundler?
|
264
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} list | xargs bundle exec knife #{provider} vm delete -y")
|
265
|
+
else
|
238
266
|
delete_command("knife node#{Spiceweasel::Config[:knife_options]} list | xargs knife #{provider} vm delete -y")
|
239
|
-
|
267
|
+
end
|
268
|
+
elsif ['digital_ocean'].member?(provider)
|
269
|
+
if bundler?
|
270
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} list | xargs bundle exec knife #{provider} droplet destroy -y")
|
271
|
+
else
|
240
272
|
delete_command("knife node#{Spiceweasel::Config[:knife_options]} list | xargs knife #{provider} droplet destroy -y")
|
273
|
+
end
|
274
|
+
else
|
275
|
+
if bundler?
|
276
|
+
delete_command("knife node#{Spiceweasel::Config[:knife_options]} list | xargs bundle exec knife #{provider} server delete -y")
|
241
277
|
else
|
242
278
|
delete_command("knife node#{Spiceweasel::Config[:knife_options]} list | xargs knife #{provider} server delete -y")
|
243
279
|
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def process_parallel(count, create_command_options, name, options, provider, run_list)
|
284
|
+
parallel = "seq #{count} | parallel -u -j 0 -v -- "
|
285
|
+
if provider.eql?('vsphere')
|
286
|
+
if bundler?
|
287
|
+
parallel += "bundle exec knife #{provider}#{Spiceweasel::Config[:knife_options]} vm clone #{options}".gsub(/\{\{n\}\}/, '{}')
|
288
|
+
else
|
289
|
+
parallel += "knife #{provider}#{Spiceweasel::Config[:knife_options]} vm clone #{options}".gsub(/\{\{n\}\}/, '{}')
|
290
|
+
end
|
291
|
+
elsif provider.eql?('kvm')
|
292
|
+
if bundler?
|
293
|
+
parallel += "bundle exec knife #{provider}#{Spiceweasel::Config[:knife_options]} vm create #{options}".gsub(/\{\{n\}\}/, '{}')
|
294
|
+
else
|
295
|
+
parallel += "knife #{provider}#{Spiceweasel::Config[:knife_options]} vm create #{options}".gsub(/\{\{n\}\}/, '{}')
|
296
|
+
end
|
297
|
+
elsif provider.eql?('digital_ocean')
|
298
|
+
if bundler?
|
299
|
+
parallel += "bundle exec knife #{provider}#{Spiceweasel::Config[:knife_options]} droplet create #{options}".gsub(/\{\{n\}\}/, '{}')
|
300
|
+
else
|
301
|
+
parallel += "knife #{provider}#{Spiceweasel::Config[:knife_options]} droplet create #{options}".gsub(/\{\{n\}\}/, '{}')
|
302
|
+
end
|
303
|
+
elsif provider.eql?('google')
|
304
|
+
if bundler?
|
305
|
+
parallel += "bundle exec knife #{provider}#{Spiceweasel::Config[:knife_options]} server create #{name} #{options}".gsub(/\{\{n\}\}/, '{}')
|
306
|
+
else
|
307
|
+
parallel += "knife #{provider}#{Spiceweasel::Config[:knife_options]} server create #{name} #{options}".gsub(/\{\{n\}\}/, '{}')
|
308
|
+
end
|
244
309
|
else
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
delete_command("knife #{provider} droplet destroy #{p_name} -y")
|
250
|
-
else
|
251
|
-
delete_command("knife #{provider} server delete #{p_name} -y")
|
252
|
-
end
|
253
|
-
delete_command("knife node#{Spiceweasel::Config[:knife_options]} delete #{p_name} -y")
|
254
|
-
delete_command("knife client#{Spiceweasel::Config[:knife_options]} delete #{p_name} -y")
|
310
|
+
if bundler?
|
311
|
+
parallel += "bundle exec knife #{provider}#{Spiceweasel::Config[:knife_options]} server create #{options}".gsub(/\{\{n\}\}/, '{}')
|
312
|
+
else
|
313
|
+
parallel += "knife #{provider}#{Spiceweasel::Config[:knife_options]} server create #{options}".gsub(/\{\{n\}\}/, '{}')
|
255
314
|
end
|
256
315
|
end
|
316
|
+
parallel += " -r '#{run_list}'" unless run_list.empty?
|
317
|
+
create_command(parallel, create_command_options)
|
257
318
|
end
|
258
319
|
|
259
|
-
#check that the knife plugin is installed
|
260
|
-
def validate_provider(provider, names,
|
261
|
-
unless knifecommands.index {|x| x.start_with?("knife #{provider}")}
|
320
|
+
# check that the knife plugin is installed
|
321
|
+
def validate_provider(provider, names, _count, options, knifecommands)
|
322
|
+
unless knifecommands.index { |x| x.start_with?("knife #{provider}") }
|
262
323
|
STDERR.puts "ERROR: 'knife #{provider}' is not a currently installed plugin for knife."
|
263
324
|
exit(-1)
|
264
325
|
end
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
326
|
+
|
327
|
+
return unless provider.eql?('google')
|
328
|
+
|
329
|
+
return unless names[1].to_i != 0 && !options.split.member?('-N')
|
330
|
+
|
331
|
+
STDERR.puts "ERROR: 'knife google' currently requires providing a name. Please use -N within the options."
|
332
|
+
exit(-1)
|
271
333
|
end
|
272
334
|
|
273
|
-
def process_chef_client(names, options, run_list)
|
335
|
+
def process_chef_client(names, options, run_list) # rubocop:disable CyclomaticComplexity
|
274
336
|
commands = []
|
275
337
|
environment = nil
|
276
338
|
protocol = 'ssh'
|
277
339
|
protooptions = ''
|
278
|
-
#protocol options
|
340
|
+
# protocol options
|
279
341
|
sudo = nil
|
280
|
-
value = nil #store last option for space-separated values
|
281
|
-
options.split
|
342
|
+
value = nil # store last option for space-separated values
|
343
|
+
options.split.each do |opt|
|
282
344
|
sudo = 'sudo ' if opt =~ /^--sudo$/
|
283
345
|
protooptions += '--no-host-key-verify ' if opt =~ /^--no-host-key-verify$/
|
284
346
|
# SSH identity file used for authentication
|
@@ -290,8 +352,8 @@ module Spiceweasel
|
|
290
352
|
if opt =~ /^-i$|^--identity-file$/
|
291
353
|
value = '-i'
|
292
354
|
else
|
293
|
-
opt.sub!(/-i/,'') if opt =~ /^-i/
|
294
|
-
opt.sub!(/--identity-file/,'') if opt =~ /^--identity-file/
|
355
|
+
opt.sub!(/-i/, '') if opt =~ /^-i/
|
356
|
+
opt.sub!(/--identity-file/, '') if opt =~ /^--identity-file/
|
295
357
|
protooptions += "-i #{opt} "
|
296
358
|
value = nil
|
297
359
|
end
|
@@ -305,8 +367,8 @@ module Spiceweasel
|
|
305
367
|
if opt =~ /^-G$|^--ssh-gateway$/
|
306
368
|
value = '-G'
|
307
369
|
else
|
308
|
-
opt.sub!(/-G/,'') if opt =~ /^-G/
|
309
|
-
opt.sub!(/--ssh-gateway/,'') if opt =~ /^--ssh-gateway/
|
370
|
+
opt.sub!(/-G/, '') if opt =~ /^-G/
|
371
|
+
opt.sub!(/--ssh-gateway/, '') if opt =~ /^--ssh-gateway/
|
310
372
|
protooptions += "-G #{opt} "
|
311
373
|
value = nil
|
312
374
|
end
|
@@ -320,8 +382,8 @@ module Spiceweasel
|
|
320
382
|
if opt =~ /^-P$|^--ssh-password$/
|
321
383
|
value = '-P'
|
322
384
|
else
|
323
|
-
opt.sub!(/-P/,'') if opt =~ /^-P/
|
324
|
-
opt.sub!(/--ssh-password/,'') if opt =~ /^--ssh-password/
|
385
|
+
opt.sub!(/-P/, '') if opt =~ /^-P/
|
386
|
+
opt.sub!(/--ssh-password/, '') if opt =~ /^--ssh-password/
|
325
387
|
protooptions += "-P #{opt} "
|
326
388
|
value = nil
|
327
389
|
end
|
@@ -335,8 +397,8 @@ module Spiceweasel
|
|
335
397
|
if opt =~ /^-p$|^--ssh-port$/
|
336
398
|
value = '-p'
|
337
399
|
else
|
338
|
-
opt.sub!(/-p/,'') if opt =~ /^-p/
|
339
|
-
opt.sub!(/--ssh-port/,'') if opt =~ /^--ssh-port/
|
400
|
+
opt.sub!(/-p/, '') if opt =~ /^-p/
|
401
|
+
opt.sub!(/--ssh-port/, '') if opt =~ /^--ssh-port/
|
340
402
|
protooptions += "-p #{opt} "
|
341
403
|
value = nil
|
342
404
|
end
|
@@ -351,8 +413,8 @@ module Spiceweasel
|
|
351
413
|
if opt =~ /^-x$|^--ssh-user$/
|
352
414
|
value = '-x'
|
353
415
|
else
|
354
|
-
opt.sub!(/-x/,'') if opt =~ /^-x/
|
355
|
-
opt.sub!(/--ssh-user/,'') if opt =~ /^--ssh-user/
|
416
|
+
opt.sub!(/-x/, '') if opt =~ /^-x/
|
417
|
+
opt.sub!(/--ssh-user/, '') if opt =~ /^--ssh-user/
|
356
418
|
protooptions += "-x #{opt} "
|
357
419
|
sudo = 'sudo ' unless opt.eql?('root')
|
358
420
|
value = nil
|
@@ -367,8 +429,8 @@ module Spiceweasel
|
|
367
429
|
if opt =~ /^-E$|^--environment$/
|
368
430
|
value = '-E'
|
369
431
|
else
|
370
|
-
opt.sub!(/-E/,'') if opt =~ /^-E/
|
371
|
-
opt.sub!(/--environment/,'') if opt =~ /^--environment/
|
432
|
+
opt.sub!(/-E/, '') if opt =~ /^-E/
|
433
|
+
opt.sub!(/--environment/, '') if opt =~ /^--environment/
|
372
434
|
environment = opt
|
373
435
|
value = nil
|
374
436
|
end
|
@@ -382,16 +444,16 @@ module Spiceweasel
|
|
382
444
|
if opt =~ /^-N$|^--node-name$/
|
383
445
|
value = '-N'
|
384
446
|
else
|
385
|
-
opt.sub!(/-N|--node-name/,'') if opt =~ /^-N|^--node-name/
|
447
|
+
opt.sub!(/-N|--node-name/, '') if opt =~ /^-N|^--node-name/
|
386
448
|
names = [opt.gsub(/{{n}}/, '*')]
|
387
449
|
value = nil
|
388
450
|
end
|
389
451
|
end
|
390
452
|
end
|
391
|
-
if names[0].start_with?(
|
392
|
-
#windows node bootstrap support
|
393
|
-
protocol = names.shift.split('_')[1] #split on 'windows_ssh' etc
|
394
|
-
sudo = nil #no sudo for Windows even if ssh is used
|
453
|
+
if names[0].start_with?('windows_')
|
454
|
+
# windows node bootstrap support
|
455
|
+
protocol = names.shift.split('_')[1] # split on 'windows_ssh' etc
|
456
|
+
sudo = nil # no sudo for Windows even if ssh is used
|
395
457
|
end
|
396
458
|
names = [] if PROVIDERS.member?(names[0])
|
397
459
|
# check options for -N, override name
|
@@ -405,10 +467,10 @@ module Spiceweasel
|
|
405
467
|
commands.push("knife #{protocol} '#{search}' '#{sudo}chef-client' #{protooptions} #{Spiceweasel::Config[:knife_options]}")
|
406
468
|
end
|
407
469
|
end
|
408
|
-
|
470
|
+
commands
|
409
471
|
end
|
410
472
|
|
411
|
-
#create the knife ssh chef-client search pattern
|
473
|
+
# create the knife ssh chef-client search pattern
|
412
474
|
def chef_client_search(name, run_list, environment)
|
413
475
|
search = []
|
414
476
|
search.push("name:#{name}") if name
|
@@ -419,16 +481,22 @@ module Spiceweasel
|
|
419
481
|
item.sub!(/::/, '\:\:')
|
420
482
|
search.push(item)
|
421
483
|
end
|
422
|
-
|
484
|
+
"#{search.join(' AND ')}"
|
423
485
|
end
|
424
486
|
|
425
|
-
#standardize the node run_list formatting
|
487
|
+
# standardize the node run_list formatting
|
426
488
|
def process_run_list(run_list)
|
427
489
|
return '' if run_list.nil?
|
428
|
-
run_list.gsub!(/ /,',')
|
429
|
-
run_list.gsub!(/,+/,',')
|
430
|
-
|
490
|
+
run_list.gsub!(/ /, ',')
|
491
|
+
run_list.gsub!(/,+/, ',')
|
492
|
+
run_list
|
431
493
|
end
|
432
494
|
|
495
|
+
# replace the {{n}} with the zero padding number
|
496
|
+
def node_numerate(name, num, count)
|
497
|
+
digits = count.to_s.length + 1
|
498
|
+
pad = sprintf("%0#{digits}i", num)
|
499
|
+
name.gsub(/\{\{n\}\}/, pad)
|
500
|
+
end
|
433
501
|
end
|
434
502
|
end
|