knife-stackbuilder 0.5.9 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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