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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7ab807fc026606708f650e207c681ea3ffb82486
4
- data.tar.gz: 71a6b26ab5974d2e1c117f04da246f150dcc4375
3
+ metadata.gz: 4f785f195082e19cce38b6ed050c7c372058cc91
4
+ data.tar.gz: 1bffb5f8a0834b0b94ed27b2df4379b7b556e71e
5
5
  SHA512:
6
- metadata.gz: 53bac33ce0fe0a52524d8dbe36d18aadd34cdecd0a0bbe66cd2bf2ff393f2741cf08f745cde95c34c962e8a6db1e56ebae016a182ae199157bb94d2014985577
7
- data.tar.gz: 52a0c878e71ee0f512fa3eb8b6213aa03a24a7772e9e2bc2c99dfc0324168998e2f96b6f6878de2c6040ae197ed22ce84bcc58414269d5a24c08c2b343e00507
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 "net/ssh"
19
- require "net/ssh/multi"
20
- require "highline/import"
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
- ssh = ssh_create(ipaddress, target.ssh_user,
43
- target.ssh_password.nil? ? target.ssh_identity_file : target.ssh_password)
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
- if knife_config['create'].has_key?('name_key')
18
- name_key = knife_config['create']['name_key']
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 knife_config['create'].has_key?('pool_key')
40
+ if create_options.has_key?('pool_key')
25
41
 
26
- pool_key = knife_config['create']['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
- config_knife(knife_cmd, knife_config['create']['options'] || { })
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
- attr_accessor :ssh_user
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
- raise ArgumentError, 'An ssh user needs to be provided for bootstrap and knife ssh.' \
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 must be provided for knife to be able ssh to a node.' \
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
- @env_key_file = "#{repo_path}/secrets/#{environment}"
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
- arg = k.gsub(/-/, '_')
202
+ unless SSH_CREDENTIAL_KEYS.include?(k)
199
203
 
200
- # Fix issue where '~/' is not expanded to home dir
201
- v.gsub!(/~\//, Dir.home + '/') if arg.end_with?('_dir') && v.start_with?('~/')
204
+ arg = k.gsub(/-/, '_')
202
205
 
203
- knife_cmd.config[arg.to_sym] = v
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] = File.join(Dir.home, '/.vagrant')
22
- knife_cmd.config[:provider] = 'virtualbox'
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] = File.join(Dir.home, '/.vagrant')
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,7 +4,7 @@ module StackBuilder::Common
4
4
 
5
5
  class Config
6
6
 
7
- QUERY_TIMEOUT = 60
7
+ QUERY_TIMEOUT = 300
8
8
  CACHE_TIMEOUT = 60
9
9
 
10
10
  class << self
@@ -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
- Marshal.dump([stdout.string, stderr.string, msg], write)
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
- return v
117
- end
118
-
119
- elsif v.start_with?('<<')
112
+ if v.start_with?('<<')
120
113
 
121
- k1 = v[/<<(\w*)[\*\$\+]/,1]
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
- include_file = key.start_with?('/') || key.nil? ? key : File.expand_path('../' + key, file)
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
- begin
154
- yaml = load_yaml(include_file, env, my)
163
+ begin
164
+ yaml = load_yaml(include_file, env, my)
155
165
 
156
- return lookup_keys.empty? ? yaml
157
- : eval('yaml' + lookup_keys.collect { |v| "['#{v}']" }.join)
166
+ return lookup_keys.empty? ? yaml
167
+ : eval('yaml' + lookup_keys.collect { |v| "['#{v}']" }.join)
158
168
 
159
- rescue Exception => msg
160
- puts "ERROR: Unable to include referenced data '#{v}'."
161
- raise msg
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 = (node_config.has_key?('attributes') ? node_config['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 = (node_config.has_key?("scale") ? node_config["scale"] : 1)
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, "The scale for node \"#{@name}\" must be greater than 0." if scale < 1
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
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Knife
4
4
  module StackBuilder
5
- VERSION = "0.5.9"
5
+ VERSION = "0.6.0"
6
6
  MAJOR, MINOR, TINY = VERSION.split('.')
7
7
  end
8
8
  end
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.5.9
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-01-14 00:00:00.000000000 Z
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.3
159
+ rubygems_version: 2.4.6
159
160
  signing_key:
160
161
  specification_version: 4
161
162
  summary: Knife Stackbuilder plugin