knife-stackbuilder 0.5.9 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/chef/knife/stack_build.rb +1 -1
- data/lib/chef/knife/stack_delete.rb +3 -4
- data/lib/stackbuilder.rb +5 -3
- data/lib/stackbuilder/chef/stack_container_node.rb +2 -2
- data/lib/stackbuilder/chef/stack_generic_node.rb +71 -9
- data/lib/stackbuilder/chef/stack_node_manager.rb +61 -52
- data/lib/stackbuilder/chef/stack_provider.rb +3 -1
- data/lib/stackbuilder/chef/stack_vagrant_node.rb +57 -7
- data/lib/stackbuilder/common/config.rb +1 -1
- data/lib/stackbuilder/common/helpers.rb +53 -26
- data/lib/stackbuilder/resources/vagrant.rb +27 -0
- data/lib/stackbuilder/stack/node_task.rb +4 -2
- data/lib/stackbuilder/stack/stack.rb +7 -1
- data/lib/stackbuilder/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f785f195082e19cce38b6ed050c7c372058cc91
|
4
|
+
data.tar.gz: 1bffb5f8a0834b0b94ed27b2df4379b7b556e71e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e36a47c1b0745433163df25eda03f5266979a3629f5b4d999d50948c576cbc11c8c72df6bcd2f79e5f5d8fc48e30d04fcb8214ebb5a5ead5e9962cfb0429c0f1
|
7
|
+
data.tar.gz: 8b1cf1c3387e9d8465f562abf578c082275bac61d06266bc6c0d73c2b78c6f1b2058ae4b742fa938b6e36d87b798ef0f85a7d4fd031620e1d8f331a21edfd766
|
@@ -56,7 +56,7 @@ class Chef
|
|
56
56
|
repo_path = getConfig(:repo_path)
|
57
57
|
environment = getConfig(:environment) || '_default'
|
58
58
|
|
59
|
-
stack_id = getConfig(:stack_id) || ENV['STACK_ID']
|
59
|
+
stack_id = getConfig(:stack_id) || ENV['STACK_ID'] || environment
|
60
60
|
stack_overrides = getConfig(:overrides) || ENV['STACK_OVERRIDES']
|
61
61
|
|
62
62
|
stack_file = name_args.first
|
@@ -13,8 +13,7 @@ class Chef
|
|
13
13
|
|
14
14
|
option :stack_id,
|
15
15
|
:long => "--stack-id STACK_ID",
|
16
|
-
:description => "The ID of the stack to delete."
|
17
|
-
:required => true
|
16
|
+
:description => "The ID of the stack to delete."
|
18
17
|
|
19
18
|
option :repo_path,
|
20
19
|
:long => "--repo_path REPO_PATH",
|
@@ -25,7 +24,7 @@ class Chef
|
|
25
24
|
def run
|
26
25
|
StackBuilder::Common::Config.logger.level = Chef::Log.logger.level
|
27
26
|
|
28
|
-
environment = getConfig(:environment) || '_default'
|
27
|
+
environment = getConfig(:environment) || '_default'
|
29
28
|
stack_file = name_args.first
|
30
29
|
|
31
30
|
if stack_file=~/[-_+=.0-9a-zA-Z]+/
|
@@ -40,7 +39,7 @@ class Chef
|
|
40
39
|
stack = StackBuilder::Stack::Stack.new(
|
41
40
|
StackBuilder::Chef::NodeProvider.new(getConfig(:repo_path), environment),
|
42
41
|
stack_file,
|
43
|
-
getConfig(:stack_id) )
|
42
|
+
getConfig(:stack_id) || ENV['STACK_ID'] || environment )
|
44
43
|
|
45
44
|
stack.destroy
|
46
45
|
end
|
data/lib/stackbuilder.rb
CHANGED
@@ -12,12 +12,14 @@ require 'fileutils'
|
|
12
12
|
require 'tmpdir'
|
13
13
|
require 'tempfile'
|
14
14
|
require "stringio"
|
15
|
+
require 'set'
|
15
16
|
require 'json'
|
16
17
|
require 'timeout'
|
17
18
|
require 'openssl'
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
19
|
+
require 'net/ssh'
|
20
|
+
require 'net/ssh/multi'
|
21
|
+
require 'ipaddr'
|
22
|
+
require 'highline/import'
|
21
23
|
|
22
24
|
require 'chef'
|
23
25
|
require 'chef/knife'
|
@@ -39,8 +39,8 @@ module StackBuilder::Chef
|
|
39
39
|
ipaddress = node.attributes['ipaddress']
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
|
-
|
42
|
+
ssh_user, ssh_password, ssh_identity_file = target.get_ssh_credentials(target_node_instance)
|
43
|
+
ssh = ssh_create(ipaddress, ssh_user, ssh_password || ssh_identity_file)
|
44
44
|
|
45
45
|
image_exists = @name==ssh_exec!(ssh, "docker images | awk '$1==\"@name\" { print $1 }'")[:out].strip
|
46
46
|
|
@@ -6,34 +6,65 @@ module StackBuilder::Chef
|
|
6
6
|
|
7
7
|
class GenericNodeManager < StackBuilder::Chef::NodeManager
|
8
8
|
|
9
|
+
def initialize(id, node_config, repo_path, environment, static_ips)
|
10
|
+
|
11
|
+
super(id, node_config, repo_path, environment)
|
12
|
+
|
13
|
+
@static_ips = static_ips
|
14
|
+
unless @static_ips.nil?
|
15
|
+
get_stack_node_resources
|
16
|
+
@nodes.each { |n| @static_ips.delete_if { |ip| ip.split('/').first==n["ipaddress"] } }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
9
20
|
def create_vm(index, name, knife_config)
|
10
21
|
|
22
|
+
pre_create = knife_config['pre_create']
|
23
|
+
pre_create.each { |c| self.run_knife_cmd(name, knife_config, c) } unless pre_create.nil?
|
24
|
+
|
11
25
|
create_class_name = knife_config['create']['class']
|
12
26
|
raise ArgumentError, "Knife plugin's server 'create' class name not provided." \
|
13
27
|
if create_class_name.nil?
|
14
28
|
|
15
29
|
knife_cmd = eval(create_class_name + '.new')
|
16
30
|
|
17
|
-
|
18
|
-
|
31
|
+
create_options = knife_config['create']
|
32
|
+
|
33
|
+
if create_options.has_key?('name_key')
|
34
|
+
name_key = create_options['name_key']
|
19
35
|
knife_cmd.config[name_key.to_sym] = name
|
20
36
|
else
|
21
37
|
knife_cmd.name_args = [ name ]
|
22
38
|
end
|
23
39
|
|
24
|
-
if
|
40
|
+
if create_options.has_key?('pool_key')
|
25
41
|
|
26
|
-
pool_key =
|
42
|
+
pool_key = create_options['pool_key']
|
27
43
|
|
28
44
|
placement_pools = knife_config['placement_pools']
|
29
45
|
raise ArgumentError, "Knife plugin 'placement_pools' list was not provided." \
|
30
46
|
if placement_pools.nil?
|
31
47
|
|
32
48
|
knife_cmd.config[pool_key.to_sym] = placement_pools[index % placement_pools.size]
|
33
|
-
end
|
49
|
+
end
|
50
|
+
|
51
|
+
self.config_knife(name, knife_cmd, knife_config['create']['options'] || { })
|
52
|
+
self.config_knife(name, knife_cmd, knife_config['options'] || { })
|
53
|
+
|
54
|
+
if create_options.has_key?('static_ip_key') && !@static_ips.nil?
|
55
|
+
|
56
|
+
static_ip = @static_ips.shift
|
57
|
+
raise Common::StackBuilder::StackBuilderError, "Static IP pool is empty." \
|
58
|
+
if static_ip.nil?
|
59
|
+
|
60
|
+
static_ip_key = create_options['static_ip_key']
|
61
|
+
ip_data = knife_config['create']['options'][static_ip_key]
|
62
|
+
static_ip += "#{ip_data}" unless ip_data.nil?
|
63
|
+
|
64
|
+
knife_cmd.config[static_ip_key.to_sym] = static_ip
|
65
|
+
end
|
34
66
|
|
35
|
-
|
36
|
-
config_knife(knife_cmd, knife_config['options'] || { })
|
67
|
+
@logger.info("Executing knife to create VM: #{knife_cmd} / #{knife_cmd.name_args} / #{knife_cmd.config}")
|
37
68
|
|
38
69
|
if knife_config['create']['synchronized']
|
39
70
|
@@sync ||= Mutex.new
|
@@ -43,6 +74,35 @@ module StackBuilder::Chef
|
|
43
74
|
else
|
44
75
|
run_knife_forked(knife_cmd)
|
45
76
|
end
|
77
|
+
|
78
|
+
post_create = knife_config['post_create']
|
79
|
+
post_create.each { |c| self.run_knife_cmd(name, knife_config, c) } unless post_create.nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
def run_knife_cmd(name, knife_config, knife_command)
|
83
|
+
|
84
|
+
class_name = knife_command['class']
|
85
|
+
raise ArgumentError, "Knife command action class name not provided: #{knife_command}" \
|
86
|
+
if class_name.nil?
|
87
|
+
|
88
|
+
knife_cmd = eval(class_name + '.new')
|
89
|
+
|
90
|
+
if knife_command.has_key?('name_key')
|
91
|
+
name_key = knife_command['name_key']
|
92
|
+
knife_cmd.config[name_key.to_sym] = name
|
93
|
+
else
|
94
|
+
knife_cmd.name_args = [ name ]
|
95
|
+
end
|
96
|
+
|
97
|
+
name_args = knife_command['args'].to_s
|
98
|
+
knife_cmd.name_args += name_args.start_with?('"') ?
|
99
|
+
name_args.split(/\"\s+\"/).collect { |s| s.gsub(/^\"|\"$/, '') } : name_args.split unless name_args.nil?
|
100
|
+
|
101
|
+
self.config_knife(name, knife_cmd, knife_command['options'] || { })
|
102
|
+
self.config_knife(name, knife_cmd, knife_config['options'] || { })
|
103
|
+
|
104
|
+
@logger.info("Executing knife: #{knife_cmd} / #{knife_cmd.name_args} / #{knife_cmd.config}")
|
105
|
+
run_knife_forked(knife_cmd)
|
46
106
|
end
|
47
107
|
|
48
108
|
def delete_vm(name, knife_config)
|
@@ -62,11 +122,13 @@ module StackBuilder::Chef
|
|
62
122
|
knife_cmd.name_args = [ name ]
|
63
123
|
end
|
64
124
|
|
65
|
-
config_knife(knife_cmd, knife_config['delete']['options'] || { })
|
66
|
-
config_knife(knife_cmd, knife_config['options'] || { })
|
125
|
+
self.config_knife(name, knife_cmd, knife_config['delete']['options'] || { })
|
126
|
+
self.config_knife(name, knife_cmd, knife_config['options'] || { })
|
67
127
|
|
68
128
|
knife_cmd.config[:yes] = true
|
69
129
|
|
130
|
+
@logger.info("Executing knife to delete VM: #{knife_cmd} / #{knife_cmd.name_args} / #{knife_cmd.config}")
|
131
|
+
|
70
132
|
if knife_config['delete']['synchronized']
|
71
133
|
@@sync ||= Mutex.new
|
72
134
|
@@sync.synchronize {
|
@@ -14,9 +14,7 @@ module StackBuilder::Chef
|
|
14
14
|
attr_accessor :run_list
|
15
15
|
attr_accessor :run_on_event
|
16
16
|
|
17
|
-
|
18
|
-
attr_accessor :ssh_password
|
19
|
-
attr_accessor :ssh_identity_file
|
17
|
+
SSH_CREDENTIAL_KEYS = Set.new(['ssh_user', 'ssh_password', 'identity_file'])
|
20
18
|
|
21
19
|
def initialize(id, node_config, repo_path, environment)
|
22
20
|
|
@@ -32,12 +30,27 @@ module StackBuilder::Chef
|
|
32
30
|
@run_on_event = node_config['run_on_event']
|
33
31
|
|
34
32
|
@knife_config = node_config['knife']
|
35
|
-
if @knife_config && @knife_config.has_key?('options')
|
36
33
|
|
37
|
-
|
34
|
+
@env_key_file = "#{repo_path}/secrets/#{environment}"
|
35
|
+
@env_key_file = nil unless File.exist?(@env_key_file)
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_name
|
39
|
+
@name
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_scale
|
43
|
+
get_stack_node_resources
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_ssh_credentials(name)
|
47
|
+
|
48
|
+
if @ssh_user.nil?
|
49
|
+
|
50
|
+
raise ArgumentError, 'An ssh user is required to create ssh sessions.' \
|
38
51
|
unless @knife_config['options'].has_key?('ssh_user')
|
39
52
|
|
40
|
-
raise ArgumentError, 'An ssh key file or password
|
53
|
+
raise ArgumentError, 'An ssh key file or password is required to create ssh sessions.' \
|
41
54
|
unless @knife_config['options'].has_key?('identity_file') ||
|
42
55
|
@knife_config['options'].has_key?('ssh_password')
|
43
56
|
|
@@ -47,16 +60,7 @@ module StackBuilder::Chef
|
|
47
60
|
@ssh_identity_file.gsub!(/~\//, Dir.home + '/') unless @ssh_identity_file.nil?
|
48
61
|
end
|
49
62
|
|
50
|
-
@
|
51
|
-
@env_key_file = nil unless File.exist?(@env_key_file)
|
52
|
-
end
|
53
|
-
|
54
|
-
def get_name
|
55
|
-
@name
|
56
|
-
end
|
57
|
-
|
58
|
-
def get_scale
|
59
|
-
get_stack_node_resources
|
63
|
+
[ @ssh_user, @ssh_password, @ssh_identity_file ]
|
60
64
|
end
|
61
65
|
|
62
66
|
def node_attributes
|
@@ -191,17 +195,30 @@ module StackBuilder::Chef
|
|
191
195
|
raise StackBuilder::Common::NotImplemented, 'HostNodeManager.delete_vm'
|
192
196
|
end
|
193
197
|
|
194
|
-
def config_knife(knife_cmd, options)
|
198
|
+
def config_knife(name, knife_cmd, options)
|
195
199
|
|
196
200
|
options.each_pair do |k, v|
|
197
201
|
|
198
|
-
|
202
|
+
unless SSH_CREDENTIAL_KEYS.include?(k)
|
199
203
|
|
200
|
-
|
201
|
-
v.gsub!(/~\//, Dir.home + '/') if arg.end_with?('_dir') && v.start_with?('~/')
|
204
|
+
arg = k.gsub(/-/, '_')
|
202
205
|
|
203
|
-
|
206
|
+
# Fix issue where '~/' is not expanded to home dir
|
207
|
+
v.gsub!(/~\//, Dir.home + '/') if arg.end_with?('_dir') && v.start_with?('~/')
|
208
|
+
|
209
|
+
knife_cmd.config[arg.to_sym] = v
|
210
|
+
end
|
204
211
|
end
|
212
|
+
|
213
|
+
unless @env_key_file.nil?
|
214
|
+
env_key = IO.read(@env_key_file)
|
215
|
+
knife_cmd.config[:secret] = env_key
|
216
|
+
end
|
217
|
+
|
218
|
+
ssh_user, ssh_password, ssh_identity_file = self.get_ssh_credentials(name)
|
219
|
+
knife_cmd.config[:ssh_user] = ssh_user
|
220
|
+
knife_cmd.config[:ssh_password] = ssh_password unless ssh_password.nil?
|
221
|
+
knife_cmd.config[:identity_file] = ssh_identity_file unless ssh_identity_file.nil?
|
205
222
|
end
|
206
223
|
|
207
224
|
private
|
@@ -213,47 +230,18 @@ module StackBuilder::Chef
|
|
213
230
|
@nodes.size
|
214
231
|
end
|
215
232
|
|
216
|
-
def knife_ssh(name, cmd)
|
217
|
-
|
218
|
-
knife_config_options = @knife_config['options'] || { }
|
219
|
-
|
220
|
-
sudo = knife_config_options['sudo'] ? 'sudo -i su -c ' : ''
|
221
|
-
|
222
|
-
ssh_cmd = "TMPFILE=`mktemp` && " +
|
223
|
-
"echo -e \"#{cmd.gsub(/\"/, "\\\"").gsub(/\$/, "\\$").gsub(/\`/, '\\' + '\`')}\" > $TMPFILE && " +
|
224
|
-
"chmod 0744 $TMPFILE && " +
|
225
|
-
"#{sudo}$TMPFILE && " +
|
226
|
-
"rm $TMPFILE"
|
227
|
-
|
228
|
-
knife_cmd = Chef::Knife::Ssh.new
|
229
|
-
knife_cmd.name_args = [ "name:#{name}", ssh_cmd ]
|
230
|
-
knife_cmd.config[:attribute] = knife_config_options['ip_attribute'] || 'ipaddress'
|
231
|
-
|
232
|
-
config_knife(knife_cmd, knife_config_options)
|
233
|
-
|
234
|
-
if @logger.info? || @logger.debug?
|
235
|
-
|
236
|
-
output = StackBuilder::Common::TeeIO.new($stdout)
|
237
|
-
error = StackBuilder::Common::TeeIO.new($stderr)
|
238
|
-
|
239
|
-
@logger.info("Running '#{cmd}' on node 'name:#{name}'.")
|
240
|
-
run_knife(knife_cmd, output, error)
|
241
|
-
else
|
242
|
-
run_knife(knife_cmd)
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
233
|
def node_search(search_query, timeout = 0)
|
247
234
|
|
248
235
|
query = Chef::Search::Query.new
|
249
236
|
escaped_query = URI.escape(search_query, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
250
237
|
|
251
238
|
if timeout>0
|
252
|
-
@logger.info("Waiting '#{search_query}' to return results.")
|
239
|
+
@logger.info("#{@name} - Waiting '#{search_query}' to return results.")
|
253
240
|
results = Timeout::timeout(timeout) {
|
254
241
|
|
255
242
|
while true do
|
256
243
|
results = query.search('node', escaped_query, nil, 0, 999999)
|
244
|
+
sleep 5
|
257
245
|
return results if results[0].size>0
|
258
246
|
end
|
259
247
|
}
|
@@ -264,5 +252,26 @@ module StackBuilder::Chef
|
|
264
252
|
results
|
265
253
|
end
|
266
254
|
|
255
|
+
def knife_ssh(name, cmd)
|
256
|
+
|
257
|
+
knife_config = @knife_config['options'] || { }
|
258
|
+
|
259
|
+
sudo = knife_config['sudo'] ? 'sudo -i su -c ' : ''
|
260
|
+
|
261
|
+
ssh_cmd = "TMPFILE=`mktemp` && " +
|
262
|
+
"echo -e \"#{cmd.gsub(/\"/, "\\\"").gsub(/\$/, "\\$").gsub(/\`/, '\\' + '\`')}\" > $TMPFILE && " +
|
263
|
+
"chmod 0744 $TMPFILE && " +
|
264
|
+
"#{sudo}$TMPFILE && " +
|
265
|
+
"rm $TMPFILE"
|
266
|
+
|
267
|
+
knife_cmd = Chef::Knife::Ssh.new
|
268
|
+
knife_cmd.name_args = [ "name:#{name}", ssh_cmd ]
|
269
|
+
knife_cmd.config[:attribute] = knife_config['ip_attribute'] || 'ipaddress'
|
270
|
+
|
271
|
+
self.config_knife(name, knife_cmd, knife_config)
|
272
|
+
|
273
|
+
@logger.info("#{@name} - Running '#{cmd}' on node 'name:#{name}'.")
|
274
|
+
run_knife(knife_cmd)
|
275
|
+
end
|
267
276
|
end
|
268
277
|
end
|
@@ -46,6 +46,8 @@ module StackBuilder::Chef
|
|
46
46
|
stack['chef']['knife_config'].each { |k,v| Chef::Config[:knife][k.to_sym] = v } \
|
47
47
|
if stack['chef'].has_key?('knife_config')
|
48
48
|
end
|
49
|
+
|
50
|
+
@static_ips = stack['static_ips']
|
49
51
|
end
|
50
52
|
|
51
53
|
def get_env_vars
|
@@ -77,7 +79,7 @@ module StackBuilder::Chef
|
|
77
79
|
end
|
78
80
|
|
79
81
|
elsif knife_config.has_key?('create')
|
80
|
-
return StackBuilder::Chef::GenericNodeManager.new(@id, node_config, @repo_path, @environment)
|
82
|
+
return StackBuilder::Chef::GenericNodeManager.new(@id, node_config, @repo_path, @environment, @static_ips)
|
81
83
|
|
82
84
|
else
|
83
85
|
return StackBuilder::Chef::NodeManager.new(@id, node_config, @repo_path, @environment)
|
@@ -6,6 +6,37 @@ module StackBuilder::Chef
|
|
6
6
|
|
7
7
|
class VagrantNodeManager < StackBuilder::Chef::NodeManager
|
8
8
|
|
9
|
+
VAGRANT_PROVIDER = 'virtualbox'
|
10
|
+
VAGRANT_DIR = File.join(Dir.home, '/.vagrant')
|
11
|
+
INSECURE_KEY_PATH = "#{VAGRANT_DIR}/insecure_key"
|
12
|
+
|
13
|
+
def vagrant_version
|
14
|
+
@@vagrant_version ||= begin
|
15
|
+
`vagrant -v`[/Vagrant\s+([0-9\.]+)/, 1]
|
16
|
+
rescue Exception => msg
|
17
|
+
raise StackBuilder::Common::StackBuilderError, "Unable to locate vagrant."
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_ssh_credentials(name)
|
22
|
+
|
23
|
+
ssh_user = @knife_config['options']['ssh_user'] || 'vagrant'
|
24
|
+
ssh_identity_file = @knife_config['options']['identity_file']
|
25
|
+
|
26
|
+
if ssh_identity_file.nil?
|
27
|
+
|
28
|
+
provider = @knife_config['options']['provider'] || VAGRANT_PROVIDER
|
29
|
+
vagrant_dir = @knife_config['options']['vagrant_dir'] || VAGRANT_DIR
|
30
|
+
|
31
|
+
ssh_identity_file = ( vagrant_version<'1.7' ? INSECURE_KEY_PATH :
|
32
|
+
"#{vagrant_dir}/#{name}/.vagrant/machines/default/#{provider}/private_key" )
|
33
|
+
else
|
34
|
+
ssh_identity_file.gsub!(/~\//, Dir.home + '/')
|
35
|
+
end
|
36
|
+
|
37
|
+
[ ssh_user, nil, ssh_identity_file ]
|
38
|
+
end
|
39
|
+
|
9
40
|
def create_vm(index, name, knife_config)
|
10
41
|
|
11
42
|
handle_vagrant_box_additions(name, knife_config)
|
@@ -18,8 +49,8 @@ module StackBuilder::Chef
|
|
18
49
|
knife_cmd.config[:distro] = 'chef-full'
|
19
50
|
knife_cmd.config[:template_file] = false
|
20
51
|
|
21
|
-
knife_cmd.config[:vagrant_dir] =
|
22
|
-
knife_cmd.config[:provider] =
|
52
|
+
knife_cmd.config[:vagrant_dir] = VAGRANT_DIR
|
53
|
+
knife_cmd.config[:provider] = VAGRANT_PROVIDER
|
23
54
|
knife_cmd.config[:memsize] = 1024
|
24
55
|
knife_cmd.config[:subnet] = '192.168.67.0/24'
|
25
56
|
knife_cmd.config[:port_forward] = { }
|
@@ -30,7 +61,10 @@ module StackBuilder::Chef
|
|
30
61
|
knife_cmd.config[:ssh_user] = 'vagrant'
|
31
62
|
knife_cmd.config[:ssh_port] = '22'
|
32
63
|
|
33
|
-
config_knife(knife_cmd, knife_config['options'] || { })
|
64
|
+
self.config_knife(name, knife_cmd, knife_config['options'] || { })
|
65
|
+
|
66
|
+
# Let vagrant use auto-generated private key for ssh during bootstrap
|
67
|
+
knife_cmd.config[:identity_file] = nil if vagrant_version>'1.7'
|
34
68
|
|
35
69
|
ip_address = knife_cmd.config[:ip_address]
|
36
70
|
knife_cmd.config[:ip_address] = ip_address[/(\d+\.\d+\.\d+\.)/, 1] + \
|
@@ -45,13 +79,10 @@ module StackBuilder::Chef
|
|
45
79
|
|
46
80
|
def delete_vm(name, knife_config)
|
47
81
|
|
48
|
-
puts "deleting #{name}"
|
49
|
-
exit 1
|
50
|
-
|
51
82
|
knife_cmd = Chef::Knife::VagrantServerDelete.new
|
52
83
|
knife_cmd.name_args = [ name ]
|
53
84
|
knife_cmd.config[:yes] = true
|
54
|
-
knife_cmd.config[:vagrant_dir] =
|
85
|
+
knife_cmd.config[:vagrant_dir] = VAGRANT_DIR
|
55
86
|
|
56
87
|
@@sync ||= Mutex.new
|
57
88
|
@@sync.synchronize {
|
@@ -76,12 +107,31 @@ module StackBuilder::Chef
|
|
76
107
|
end
|
77
108
|
end
|
78
109
|
|
110
|
+
def config_knife(name, knife_cmd, options)
|
111
|
+
|
112
|
+
super(name, knife_cmd, options)
|
113
|
+
|
114
|
+
# Add ohai plugin to change the ohai ipaddress
|
115
|
+
# value to the non NAT'ed eth1 interface. This
|
116
|
+
# is required so you can SSH into vagrant VMs
|
117
|
+
# via knife ssh
|
118
|
+
ohai_plugin_resource = File.expand_path('../../resources/vagrant.rb', __FILE__)
|
119
|
+
|
120
|
+
knife_cmd.config[:vagrant_config] = \
|
121
|
+
"config.vm.provision \"file\", source: \"#{ohai_plugin_resource}\", destination: \"~/vagrant.rb\"::" +
|
122
|
+
'config.vm.provision "shell", inline: "mkdir -p /etc/chef/ohai_plugins"::' +
|
123
|
+
'config.vm.provision "shell", inline: "mv /home/vagrant/vagrant.rb /etc/chef/ohai_plugins"::' +
|
124
|
+
'config.vm.provision "shell", inline: \'echo {\"primary_nic\":\"eth1\"} > /etc/chef/ohai_plugins/vagrant.json\'::' +
|
125
|
+
(knife_cmd.config[:vagrant_config] || '')
|
126
|
+
end
|
127
|
+
|
79
128
|
def handle_vagrant_box_additions(name, knife_config)
|
80
129
|
|
81
130
|
# Create add-on provider specific infrastructure
|
82
131
|
knife_options = knife_config['options']
|
83
132
|
provider = knife_options['provider']
|
84
133
|
|
134
|
+
# Create disks for vagrant vms on vmware if requested
|
85
135
|
if !provider.nil? && provider.start_with?('vmware')
|
86
136
|
|
87
137
|
vmx_customize = knife_options['vmx_customize']
|
@@ -4,6 +4,8 @@ module StackBuilder::Common
|
|
4
4
|
|
5
5
|
module Helpers
|
6
6
|
|
7
|
+
MAGIC_VARS = Set.new(%w(env my))
|
8
|
+
|
7
9
|
#
|
8
10
|
# Returns whether platform is a nix OS
|
9
11
|
#
|
@@ -48,7 +50,8 @@ module StackBuilder::Common
|
|
48
50
|
yield(job)
|
49
51
|
Marshal.dump([stdout.string, stderr.string], write)
|
50
52
|
rescue Exception => msg
|
51
|
-
|
53
|
+
StackBuilder::Common::Config.logger.debug("Exception in forked job: #{msg}\n" + msg.backtrace.join("\n\t"))
|
54
|
+
Marshal.dump([stdout.string, stderr.string, StackBuilder::Common::StackBuilderError.new(msg.to_s) ], write)
|
52
55
|
ensure
|
53
56
|
$stdout = previous_stdout
|
54
57
|
$stderr = previous_stderr
|
@@ -91,7 +94,7 @@ module StackBuilder::Common
|
|
91
94
|
def load_yaml(file, env_vars, my = nil)
|
92
95
|
|
93
96
|
yaml = YAML.load_file(file)
|
94
|
-
eval_map_values(yaml, env_vars, file, my)
|
97
|
+
eval_map_values(yaml, env_vars, file, my || yaml)
|
95
98
|
end
|
96
99
|
|
97
100
|
#
|
@@ -104,21 +107,11 @@ module StackBuilder::Common
|
|
104
107
|
|
105
108
|
if v.is_a?(String)
|
106
109
|
|
107
|
-
if v=~/#\{.*\}/
|
108
|
-
begin
|
109
|
-
return eval("\"#{v.gsub(/\"/, "\\\"")}\"")
|
110
|
-
|
111
|
-
rescue Exception => msg
|
112
|
-
|
113
|
-
StackBuilder::Common::Config.logger.debug( "Error evaluating configuration " +
|
114
|
-
"variable '#{v}': #{msg}\nenv = #{env}\nmy = #{my}")
|
110
|
+
v = eval("\"#{v.gsub(/\"/, "\\\"")}\"") if v=~/#\{.*\}/
|
115
111
|
|
116
|
-
|
117
|
-
end
|
118
|
-
|
119
|
-
elsif v.start_with?('<<')
|
112
|
+
if v.start_with?('<<')
|
120
113
|
|
121
|
-
k1 = v[/<<(\w*)[
|
114
|
+
k1 = v[/<<(\w*)[\*\$\@\+]/,1]
|
122
115
|
env_val = k1.nil? || k1.empty? ? nil : ENV[k1]
|
123
116
|
|
124
117
|
i = k1.length + 3
|
@@ -144,27 +137,45 @@ module StackBuilder::Common
|
|
144
137
|
end
|
145
138
|
return v
|
146
139
|
|
140
|
+
when '@'
|
141
|
+
if env_val.nil?
|
142
|
+
tuple = k2.split(':')
|
143
|
+
else
|
144
|
+
tuple = env_val.split(':')
|
145
|
+
end
|
146
|
+
|
147
|
+
ipaddress = IPAddr.new(tuple[0])
|
148
|
+
num_ips, cidr_mask = tuple[1].split('/')
|
149
|
+
|
150
|
+
ipaddresses = [ ipaddress ]
|
151
|
+
ipaddresses += (0..num_ips.to_i-2).to_a.collect { |i| ipaddress = ipaddress.succ }
|
152
|
+
return ipaddresses.collect { |i| i.to_s + (cidr_mask.nil? ? '' : "/#{cidr_mask}") }
|
153
|
+
|
147
154
|
when '+'
|
148
|
-
lookup_keys = (env_val || k2).split(/[\[\]]/).reject { |k| k.empty? }
|
155
|
+
lookup_keys = (env_val || k2).split(/[\[\]']/).reject { |k| k.empty? }
|
149
156
|
|
150
157
|
key = lookup_keys.shift
|
151
|
-
|
158
|
+
if MAGIC_VARS.include?(key)
|
159
|
+
v = eval(key + lookup_keys.collect { |v| "['#{v}']" }.join)
|
160
|
+
else
|
161
|
+
include_file = key.start_with?('/') || key.nil? ? key : File.expand_path('../' + key, file)
|
152
162
|
|
153
|
-
|
154
|
-
|
163
|
+
begin
|
164
|
+
yaml = load_yaml(include_file, env, my)
|
155
165
|
|
156
|
-
|
157
|
-
|
166
|
+
return lookup_keys.empty? ? yaml
|
167
|
+
: eval('yaml' + lookup_keys.collect { |v| "['#{v}']" }.join)
|
158
168
|
|
159
|
-
|
160
|
-
|
161
|
-
|
169
|
+
rescue Exception => msg
|
170
|
+
puts "ERROR: Unable to include referenced data '#{v}'."
|
171
|
+
raise msg
|
172
|
+
end
|
162
173
|
end
|
163
|
-
else
|
164
|
-
return v
|
165
174
|
end
|
166
175
|
end
|
167
176
|
|
177
|
+
return v
|
178
|
+
|
168
179
|
elsif v.is_a?(Hash)
|
169
180
|
|
170
181
|
new_keys = { }
|
@@ -189,6 +200,13 @@ module StackBuilder::Common
|
|
189
200
|
end
|
190
201
|
|
191
202
|
v
|
203
|
+
|
204
|
+
rescue Exception => msg
|
205
|
+
|
206
|
+
StackBuilder::Common::Config.logger.debug( "Error evaluating configuration " +
|
207
|
+
"variable '#{v}': #{msg}\nenv = #{env}\nmy = #{my}")
|
208
|
+
|
209
|
+
v
|
192
210
|
end
|
193
211
|
|
194
212
|
#
|
@@ -375,6 +393,15 @@ module StackBuilder::Common
|
|
375
393
|
#
|
376
394
|
def run_knife(knife_cmd, output = StringIO.new, error = StringIO.new)
|
377
395
|
|
396
|
+
logger = StackBuilder::Common::Config.logger
|
397
|
+
if logger.info? || logger.debug?
|
398
|
+
output = StackBuilder::Common::TeeIO.new($stdout)
|
399
|
+
error = StackBuilder::Common::TeeIO.new($stderr)
|
400
|
+
else
|
401
|
+
output = StringIO.new
|
402
|
+
error = StringIO.new
|
403
|
+
end
|
404
|
+
|
378
405
|
knife_cmd.ui = Chef::Knife::UI.new(output, error, STDIN, knife_cmd.config) \
|
379
406
|
unless output.nil? && error.nil?
|
380
407
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Ohai.plugin(:Vboxipaddress) do
|
2
|
+
|
3
|
+
provides "ipaddress"
|
4
|
+
depends "ipaddress", "network/interfaces", "virtualization/system", "etc/passwd"
|
5
|
+
|
6
|
+
Chef::Log.info("Running Vagrant plugin to reset node ipaddress attribute.")
|
7
|
+
|
8
|
+
if File.exist?('/etc/chef/ohai_plugins/vagrant.json')
|
9
|
+
vagrant = JSON.parse(IO.read('/etc/chef/ohai_plugins/vagrant.json'))
|
10
|
+
|
11
|
+
collect_data(:default) do
|
12
|
+
if virtualization["system"] == "vbox" || virtualization["system"] == "vmware"
|
13
|
+
if etc["passwd"].any? { |k,v| k == "vagrant"}
|
14
|
+
primary_nic = vagrant["primary_nic"]
|
15
|
+
if primary_nic && network["interfaces"][primary_nic]
|
16
|
+
network["interfaces"][primary_nic]["addresses"].each do |ip, params|
|
17
|
+
if params['family'] == ('inet')
|
18
|
+
Chef::Log.info("Setting node ipaddress attribute to: #{ip}")
|
19
|
+
ipaddress ip
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -9,6 +9,7 @@ module StackBuilder::Stack
|
|
9
9
|
attr_reader :name
|
10
10
|
|
11
11
|
attr_accessor :scale
|
12
|
+
attr_accessor :max_scale
|
12
13
|
attr_accessor :prev_scale
|
13
14
|
attr_accessor :sync
|
14
15
|
|
@@ -38,7 +39,7 @@ module StackBuilder::Stack
|
|
38
39
|
@counter = 0
|
39
40
|
|
40
41
|
@name = node_config['node']
|
41
|
-
@attributes =
|
42
|
+
@attributes = node_config['attributes'] || { }
|
42
43
|
|
43
44
|
case node_config['sync']
|
44
45
|
when "first"
|
@@ -51,10 +52,11 @@ module StackBuilder::Stack
|
|
51
52
|
|
52
53
|
current_scale = manager.get_scale
|
53
54
|
if current_scale==0
|
54
|
-
@scale =
|
55
|
+
@scale = node_config["scale"] || 1
|
55
56
|
else
|
56
57
|
@scale = current_scale
|
57
58
|
end
|
59
|
+
@max_scale = node_config["max_scale"] || @scale
|
58
60
|
|
59
61
|
raise ArgumentError, "The scale for node \"#{@name}\" must be greater than 0." if @scale < 1
|
60
62
|
@prev_scale = @scale
|
@@ -104,7 +104,13 @@ module StackBuilder::Stack
|
|
104
104
|
raise StackBuilder::Common::StackBuilderError, "Invalid node name \"#{name}'\"." if node.nil?
|
105
105
|
|
106
106
|
unless scale.nil?
|
107
|
-
raise ArgumentError,
|
107
|
+
raise ArgumentError, \
|
108
|
+
"The scale for node \"#{node.name}\" must be greater than 0." \
|
109
|
+
if scale < 1
|
110
|
+
raise ArgumentError, \
|
111
|
+
"The scale for node \"#{node.name}\" cannot be greater than #{node.max_scale}." \
|
112
|
+
if scale > node.max_scale
|
113
|
+
|
108
114
|
node.scale = scale
|
109
115
|
end
|
110
116
|
end
|
data/lib/stackbuilder/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife-stackbuilder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mevan Samaratunga
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef
|
@@ -131,6 +131,7 @@ files:
|
|
131
131
|
- lib/stackbuilder/resources/Environment.rb.erb
|
132
132
|
- lib/stackbuilder/resources/Stack.yml.erb
|
133
133
|
- lib/stackbuilder/resources/openssl.cnf
|
134
|
+
- lib/stackbuilder/resources/vagrant.rb
|
134
135
|
- lib/stackbuilder/stack/node_manager.rb
|
135
136
|
- lib/stackbuilder/stack/node_provider.rb
|
136
137
|
- lib/stackbuilder/stack/node_task.rb
|
@@ -155,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
156
|
version: '0'
|
156
157
|
requirements: []
|
157
158
|
rubyforge_project:
|
158
|
-
rubygems_version: 2.4.
|
159
|
+
rubygems_version: 2.4.6
|
159
160
|
signing_key:
|
160
161
|
specification_version: 4
|
161
162
|
summary: Knife Stackbuilder plugin
|