vagabond 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/CHANGELOG.md +18 -0
  2. data/README.md +125 -4
  3. data/bin/vagabond +43 -16
  4. data/lib/vagabond/actions/cluster.rb +66 -0
  5. data/lib/vagabond/actions/create.rb +12 -7
  6. data/lib/vagabond/actions/destroy.rb +69 -15
  7. data/lib/vagabond/actions/init.rb +75 -0
  8. data/lib/vagabond/actions/provision.rb +4 -2
  9. data/lib/vagabond/actions/status.rb +33 -22
  10. data/lib/vagabond/actions/up.rb +8 -1
  11. data/lib/vagabond/bootstraps/server-zero.erb +20 -0
  12. data/lib/vagabond/bootstraps/server.erb +3 -2
  13. data/lib/vagabond/constants.rb +0 -15
  14. data/lib/vagabond/cookbooks/lxc/CHANGELOG.md +16 -0
  15. data/lib/vagabond/cookbooks/lxc/Gemfile +3 -2
  16. data/lib/vagabond/cookbooks/lxc/Gemfile.lock +30 -121
  17. data/lib/vagabond/cookbooks/lxc/README.md +43 -14
  18. data/lib/vagabond/cookbooks/lxc/attributes/default.rb +3 -3
  19. data/lib/vagabond/cookbooks/lxc/files/default/lxc-awesome-ephemeral +499 -0
  20. data/lib/vagabond/cookbooks/lxc/libraries/lxc.rb +223 -58
  21. data/lib/vagabond/cookbooks/lxc/libraries/lxc_file_config.rb +3 -0
  22. data/lib/vagabond/cookbooks/lxc/libraries/monkey.rb +51 -0
  23. data/lib/vagabond/cookbooks/lxc/metadata.rb +6 -5
  24. data/lib/vagabond/cookbooks/lxc/providers/config.rb +9 -16
  25. data/lib/vagabond/cookbooks/lxc/providers/container.rb +241 -229
  26. data/lib/vagabond/cookbooks/lxc/providers/default.rb +57 -0
  27. data/lib/vagabond/cookbooks/lxc/providers/ephemeral.rb +40 -0
  28. data/lib/vagabond/cookbooks/lxc/providers/fstab.rb +13 -54
  29. data/lib/vagabond/cookbooks/lxc/providers/interface.rb +13 -67
  30. data/lib/vagabond/cookbooks/lxc/providers/service.rb +14 -14
  31. data/lib/vagabond/cookbooks/lxc/recipes/default.rb +17 -4
  32. data/lib/vagabond/cookbooks/lxc/recipes/install_dependencies.rb +1 -1
  33. data/lib/vagabond/cookbooks/lxc/resources/config.rb +2 -2
  34. data/lib/vagabond/cookbooks/lxc/resources/container.rb +31 -6
  35. data/lib/vagabond/cookbooks/lxc/resources/default.rb +12 -0
  36. data/lib/vagabond/cookbooks/lxc/resources/ephemeral.rb +13 -0
  37. data/lib/vagabond/cookbooks/lxc/resources/fstab.rb +2 -1
  38. data/lib/vagabond/cookbooks/lxc/resources/interface.rb +6 -3
  39. data/lib/vagabond/cookbooks/lxc/resources/service.rb +1 -1
  40. data/lib/vagabond/cookbooks/lxc/templates/default/file_content.erb +2 -0
  41. data/lib/vagabond/cookbooks/lxc/templates/default/interface.erb +9 -3
  42. data/lib/vagabond/cookbooks/vagabond/README.md +10 -0
  43. data/lib/vagabond/cookbooks/vagabond/attributes/default.rb +1 -0
  44. data/lib/vagabond/cookbooks/vagabond/files/default/lxc-centos +13 -6
  45. data/lib/vagabond/cookbooks/vagabond/metadata.rb +1 -0
  46. data/lib/vagabond/cookbooks/vagabond/recipes/default.rb +46 -4
  47. data/lib/vagabond/cookbooks/vagabond/recipes/zero.rb +9 -0
  48. data/lib/vagabond/errors.rb +23 -0
  49. data/lib/vagabond/helpers.rb +41 -14
  50. data/lib/vagabond/internal_configuration.rb +120 -27
  51. data/lib/vagabond/kitchen.rb +143 -63
  52. data/lib/vagabond/knife.rb +8 -5
  53. data/lib/vagabond/layout.rb +16 -0
  54. data/lib/vagabond/monkey/kitchen_config.rb +23 -0
  55. data/lib/vagabond/server.rb +79 -63
  56. data/lib/vagabond/spec.rb +345 -0
  57. data/lib/vagabond/uploader.rb +30 -0
  58. data/lib/vagabond/uploader/berkshelf.rb +53 -0
  59. data/lib/vagabond/uploader/knife.rb +24 -0
  60. data/lib/vagabond/uploader/librarian.rb +31 -0
  61. data/lib/vagabond/vagabond.rb +30 -11
  62. data/lib/vagabond/vagabondfile.rb +40 -5
  63. data/lib/vagabond/version.rb +1 -1
  64. data/vagabond.gemspec +5 -2
  65. metadata +75 -15
  66. data/lib/vagabond/cookbooks/lxc/resources/#container.rb# +0 -28
  67. data/lib/vagabond/cookbooks/lxc/test/kitchen/Kitchenfile +0 -7
  68. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/metadata.rb +0 -2
  69. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/centos_lxc.rb +0 -0
  70. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/chef-bootstrap.rb +0 -0
  71. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/lxc_files.rb +0 -0
  72. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/lxc_templates.rb +0 -0
  73. data/lib/vagabond/cookbooks/lxc/test/kitchen/cookbooks/lxc_test/recipes/ubuntu_lxc.rb +0 -0
@@ -0,0 +1,12 @@
1
+ actions :create, :delete, :clone
2
+ default_action :create
3
+
4
+ attribute :template, :kind_of => String, :default => 'ubuntu'
5
+ attribute :template_opts, :kind_of => Hash, :default => {}
6
+ attribute :base_container, :kind_of => String
7
+
8
+ # Backing store options. Not yet in use
9
+ attribute :fstype, :kind_of => String, :default => 'ext4'
10
+ attribute :fssize, :kind_of => String, :default => '2G'
11
+ attribute :vgname, :kind_of => String
12
+ attribute :lvname, :kind_of => String
@@ -0,0 +1,13 @@
1
+ actions :run
2
+ default_action :run
3
+
4
+ attribute :command, :kind_of => String, :required => true
5
+ attribute :bind_directory, :kind_of => String
6
+ attribute :base_container, :kind_of => String, :required => true
7
+ attribute :background, :kind_of => [TrueClass,FalseClass], :default => false
8
+ attribute :union_type, :equal_to => %w(aufs overlayfs), :default => 'overlayfs'
9
+ attribute :user, :kind_of => String, :default => 'root'
10
+ attribute :key, :kind_of => String, :default => '/opt/hw-lxc-config/id_rsa'
11
+ attribute :host_rootfs, :kind_of => String
12
+ attribute :virtual_device, :kind_of => Numeric
13
+ attribute :stream_output, :kind_of => [TrueClass,FalseClass,IO]
@@ -8,4 +8,5 @@ attribute :type, :kind_of => String, :required => true
8
8
  attribute :options, :kind_of => [String, Array]
9
9
  attribute :dump, :kind_of => Numeric, :default => 0
10
10
  attribute :pass, :kind_of => Numeric, :default => 0
11
- attribute :_lxc
11
+ attribute :auto_join_rootfs_mount, :kind_of => [TrueClass,FalseClass], :default => true
12
+ attribute :create_mount_point, :kind_of => [TrueClass,FalseClass], :default => true
@@ -5,6 +5,9 @@ attribute :container, :kind_of => String, :required => true
5
5
  attribute :device, :kind_of => String, :required => true
6
6
  attribute :auto, :kind_of => [TrueClass, FalseClass], :default => true
7
7
  attribute :dynamic, :kind_of => [TrueClass, FalseClass], :default => false
8
- attribute :address, :regex => %r{\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}}
9
- attribute :gateway, :regex => %r{\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}}
10
- attribute :netmask, :regex => %r{\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}}, :default => '255.255.255.0'
8
+ attribute :address, :kind_of => String
9
+ attribute :gateway, :kind_of => String
10
+ attribute :up, :kind_of => String
11
+ attribute :down, :kind_of => String
12
+ attribute :netmask, :kind_of => [String,Numeric]
13
+ attribute :ipv6, :kind_of => [TrueClass,FalseClass], :default => false
@@ -2,4 +2,4 @@ actions :start, :stop, :halt, :restart, :freeze, :unfreeze
2
2
  default_action :start
3
3
 
4
4
  attribute :service_name, :kind_of => String
5
- attribute :_lxc
5
+
@@ -0,0 +1,2 @@
1
+ # Chef generated key file
2
+ <%= ::File.read(@path) %>
@@ -4,18 +4,24 @@
4
4
  auto lo
5
5
  iface lo inet loopback
6
6
 
7
- <% node[:lxc][:interfaces][@container].each do |net_set| -%>
7
+ <% node.run_state[:lxc][:interfaces][@container].each do |net_set| -%>
8
8
  <% if net_set[:auto] -%>
9
9
  auto <%= net_set[:device] %>
10
10
  <% end -%>
11
11
  <% if net_set[:dynamic] -%>
12
- iface <%= net_set[:device] %> inet dhcp
12
+ iface <%= net_set[:device] %> inet<%= '6' if net_set[:ipv6] %> dhcp
13
13
  <% else -%>
14
- iface <%= net_set[:device] %> inet static
14
+ iface <%= net_set[:device] %> inet<%= '6' if net_set[:ipv6] %> static
15
15
  address <%= net_set[:address] %>
16
16
  <% if net_set[:gateway] -%>
17
17
  gateway <%= net_set[:gateway] %>
18
18
  <% end -%>
19
19
  netmask <%= net_set[:netmask] %>
20
+ <% if net_set[:up] -%>
21
+ up <%= net_set[:up] %>
22
+ <% end -%>
23
+ <% if net_set[:down] -%>
24
+ down <%= net_set[:down] %>
25
+ <% end -%>
20
26
  <% end -%>
21
27
  <% end %>
@@ -0,0 +1,10 @@
1
+ # Vagabond
2
+
3
+ This cookbooks is used internally by the vagabond project.
4
+ It's general intention is to be used in that fashion, but
5
+ if you want to do something else with it, go nuts.
6
+
7
+ ## Info
8
+
9
+ * Repository: https://github.com/chrisroberts/chef-vagabond
10
+ * IRC: spox @ Freenode
@@ -15,3 +15,4 @@ default[:vagabond][:bases][:debian_6][:create_environment] = {'SUITE' => 'squeez
15
15
  default[:vagabond][:bases][:debian_7][:template] = 'debian'
16
16
  default[:vagabond][:bases][:debian_7][:create_environment] = {'SUITE' => 'wheezy'}
17
17
  default[:vagabond][:customs] = {}
18
+ default[:vagabond][:server_base] = true
@@ -156,16 +156,23 @@ YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck"
156
156
  PKG_LIST="yum initscripts passwd rsyslog vim-minimal dhclient chkconfig"
157
157
  PKG_LIST="$PKG_LIST rootfiles policycoreutils centos-release openssh-server avahi"
158
158
  MIRRORLIST_URL="http://mirrorlist.centos.org/?release=$release.$releaseminor&arch=$arch&repo=os"
159
-
159
+
160
+ FOUND_MIRRORS=$(curl -s -S -f "$MIRRORLIST_URL")
161
+ AVAIL_MIRRORS="${FOUND_MIRRORS} http://vault.centos.org/$release.$releaseminor/os/$arch"
162
+
160
163
  DOWNLOAD_OK=no
161
- for trynumber in 1 2 3; do
162
- [ $trynumber != 1 ] && echo "Trying again..."
163
- MIRROR_URL=$(curl -s -S -f "$MIRRORLIST_URL" | head -n2 | tail -n1)
164
+ for MIRROR_URL in $AVAIL_MIRRORS; do
164
165
  if [ $? -ne 0 ] || [ -z "$MIRROR_URL" ]; then
165
166
  echo "Failed to get a mirror"
166
167
  continue
167
168
  fi
168
- RELEASE_URL="$MIRROR_URL/Packages/centos-release-$release-$releaseminor.el6.centos.9.$arch.rpm"
169
+ if [ $release = "6" ]; then
170
+ PACKAGE_NAME=`wget -q -O - ${MIRROR_URL}/Packages/ | grep centos-release-${release}.${releaseminor} | sed -r 's/.+rpm">//g' | sed -r 's/<.+//g'`
171
+ RELEASE_URL="$MIRROR_URL/Packages/${PACKAGE_NAME}"
172
+ else
173
+ PACKAGE_NAME=`wget -q -O - ${MIRROR_URL}/CentOS/ | grep centos-release-${release}.${releaseminor} | sed -r 's/.+rpm">//g' | sed -r 's/<.+//g'`
174
+ RELEASE_URL="$MIRROR_URL/CentOS/${PACKAGE_NAME}"
175
+ fi
169
176
  echo "Fetching from $RELEASE_URL"
170
177
  curl -f "$RELEASE_URL" > $INSTALL_ROOT/centos-release-$release-$releaseminor.centos.$arch.rpm
171
178
  if [ $? -ne 0 ]; then
@@ -412,7 +419,7 @@ fi
412
419
 
413
420
  rootfs_path=$path/rootfs
414
421
  config_path=$default_path/$name
415
- cache=$cache_base/$release
422
+ cache=$cache_base/$release.$releaseminor
416
423
 
417
424
  revert()
418
425
  {
@@ -1,5 +1,6 @@
1
1
  name 'vagabond'
2
2
  version '1.0.0'
3
+ license 'Apache 2.0'
3
4
  maintainer 'Chris Roberts'
4
5
  maintainer_email 'chrisroberts.code@gmail.com'
5
6
 
@@ -1,3 +1,37 @@
1
+
2
+ # TODO: Move this to lxc cookbook proper at some point
3
+ # TODO: Test this on fresh node to ensure start up scripts actuall do
4
+ # what they are expected to
5
+ =begin
6
+ dpkg_autostart 'lxc' do
7
+ allow false
8
+ end
9
+
10
+ dpkg_autostart 'lxc-net' do
11
+ allow false
12
+ end
13
+ =end
14
+ # Start at 0 and increment up if found
15
+ unless(node[:network][:interfaces][:lxcbr0])
16
+ max = node.network.interfaces.map do |name, val|
17
+ Array(val[:routes]).map do |route|
18
+ if(route[:family] == 'inet' && route[:destination].start_with?('10.0'))
19
+ route[:destination].split('/').first.split('.')[3].to_i
20
+ end
21
+ end
22
+ end.compact.max
23
+
24
+ node.default[:vagabond][:lxc_network][:oct] = max ? max + 1 : 0
25
+
26
+ # Test for existing bridge. Use different subnet if found
27
+ l_net = "10.0.#{node[:vagabond][:lxc_network][:oct]}"
28
+
29
+ node.set[:lxc][:addr] = "#{l_net}.1"
30
+ node.set[:lxc][:network] = "#{l_net}.0/24"
31
+ node.set[:lxc][:dhcp_range] = "#{l_net}.2,#{l_net}.199"
32
+ node.set[:lxc][:dhcp_max] = '199'
33
+ end
34
+
1
35
  include_recipe 'lxc'
2
36
 
3
37
  ruby_block 'LXC template: lxc-centos' do
@@ -57,11 +91,21 @@ node[:vagabond][:bases].each do |name, options|
57
91
  end
58
92
  end
59
93
 
94
+ lxc_container 'chef-server' do
95
+ clone 'ubuntu_1204'
96
+ initialize_commands [
97
+
98
+ ]
99
+ only_if do
100
+ node[:vagabond][:server_base]
101
+ end
102
+ end
103
+
60
104
  node[:vagabond][:customs].each do |name, options|
61
105
 
62
106
  lxc_container name do
63
- action :clone
64
- base_container options[:base]
107
+ action :create
108
+ clone options[:base]
65
109
  end
66
110
 
67
111
  if(options[:memory])
@@ -76,5 +120,3 @@ node[:vagabond][:customs].each do |name, options|
76
120
  end
77
121
  end
78
122
  end
79
-
80
-
@@ -0,0 +1,9 @@
1
+ execute 'apt-get update'
2
+ package 'build-essential'
3
+ gem_package 'chef-zero'
4
+
5
+ execute 'start chef-zero' do
6
+ command "start-stop-daemon --background --start --quiet --exec #{File.join(node[:languages][:ruby][:bin_dir],'chef-zero')} -- -H #{node[:ipaddress]} -p 80 start"
7
+ not_if 'netstat -lpt | grep "tcp[[:space:]]" | grep ruby'
8
+ end
9
+
@@ -0,0 +1,23 @@
1
+ module Vagabond
2
+ class VagabondError < StandardError
3
+ class << self
4
+ attr_accessor :exit_code
5
+ end
6
+ def exit_code
7
+ self.class.exit_code
8
+ end
9
+ end
10
+
11
+ class VagabondError
12
+ %w(
13
+ reserved_name invalid_name invalid_base_template
14
+ invalid_action invalid_template kitchen_missing_yml
15
+ kitchen_no_cookbook_args kitchen_too_many_args
16
+ kitchen_invalid_platform missing_node_name cluster_invalid
17
+ kitchen_test_failed host_provision_failed spec_failed
18
+ ).each_with_index do |klass_name, i|
19
+ klass = klass_name.split('_').map(&:capitalize).join
20
+ self.class_eval("class #{klass} < VagabondError; self.exit_code = #{i + 1}; end")
21
+ end
22
+ end
23
+ end
@@ -1,41 +1,68 @@
1
1
  require 'vagabond/constants'
2
+ require 'tmpdir'
3
+ require 'uuidtools'
2
4
 
3
5
  module Vagabond
4
6
  module Helpers
7
+
8
+ RAND_CHARS = ('a'..'z').map(&:to_s) + ('A'..'Z').map(&:to_s) + (0..9).map(&:to_s)
9
+ GEN_NAME_LENGTH = 10
10
+
5
11
  private
12
+
13
+ def base_setup
14
+ @options = options.dup
15
+ @vagabondfile = Vagabondfile.new(options[:vagabond_file], :allow_missing)
16
+ Lxc.use_sudo = sudo
17
+ options[:sudo] = sudo
18
+ setup_ui
19
+ @internal_config = InternalConfiguration.new(@vagabondfile, ui, options)
20
+ end
21
+
6
22
  def sudo
7
- case @vagabondfile[:sudo]
8
- when TrueClass
9
- 'sudo '
23
+ case vagabondfile[:sudo]
24
+ when FalseClass
25
+ ''
10
26
  when String
11
- "#{@vagabondfile[:sudo]} "
27
+ "#{vagabondfile[:sudo]} "
28
+ else
29
+ 'sudo '
12
30
  end
13
31
  end
14
32
 
15
33
  def debug(s)
16
- ui.info "#{ui.color('DEBUG:', :red, :bold)} #{s}" if options[:debug]
34
+ ui.info "#{ui.color('DEBUG:', :red, :bold)} #{s}" if options[:debug] && ui
35
+ end
36
+
37
+ def random_name(n=nil)
38
+ n = name unless n
39
+ [n, SecureRandom.hex].compact.join('-')
17
40
  end
18
41
 
19
42
  def generated_name(n=nil)
43
+ seed = vagabondfile.directory.chars.map(&:ord).inject(&:+)
44
+ srand(seed)
20
45
  n = name unless n
21
46
  if(@_gn.nil? || @_gn[n].nil?)
22
47
  @_gn ||= Mash.new
23
- s = Digest::MD5.new
24
- s << @vagabondfile.path
25
- @_gn[n] = "#{n}-#{s.hexdigest}"
48
+ @_gn[n] = "#{n}-"
49
+ GEN_NAME_LENGTH.times do
50
+ @_gn[n] << RAND_CHARS[rand(RAND_CHARS.size)]
51
+ end
26
52
  end
27
53
  @_gn[n]
28
54
  end
29
55
 
30
- def setup_ui(ui=nil)
31
- unless(ui)
56
+ def setup_ui(*args)
57
+ unless(args.first.is_a?(Chef::Knife::UI))
32
58
  Chef::Config[:color] = options[:color].nil? ? true : options[:color]
33
59
  @ui = Chef::Knife::UI.new(STDOUT, STDERR, STDIN, {})
34
60
  else
35
- @ui = ui
61
+ @ui = args.first
36
62
  end
37
63
  options[:debug] = STDOUT if options[:debug]
38
- self.class.ui = @ui
64
+ self.class.ui = @ui unless args.include?(:no_class_set)
65
+ @ui
39
66
  end
40
67
 
41
68
  def execute
@@ -43,7 +70,7 @@ module Vagabond
43
70
  send(@action)
44
71
  else
45
72
  ui.error "Invalid action received: #{@action}"
46
- exit EXIT_CODES[:invalid_action]
73
+ raise VagabondError::InvalidAction.new(@action)
47
74
  end
48
75
  end
49
76
 
@@ -75,9 +102,9 @@ module Vagabond
75
102
  class << self
76
103
  attr_accessor :ui
77
104
  end
105
+ attr_accessor :vagabondfile, :internal_config, :name, :ui
78
106
  end
79
107
  end
80
108
  end
81
-
82
109
  end
83
110
  end
@@ -2,6 +2,7 @@ require 'digest/sha2'
2
2
  require 'json'
3
3
  require 'vagabond/helpers'
4
4
  require 'vagabond/constants'
5
+ require 'chef/mixin/deep_merge'
5
6
 
6
7
  module Vagabond
7
8
  class InternalConfiguration
@@ -23,17 +24,36 @@ module Vagabond
23
24
  @config = Mash.new(
24
25
  :mappings => Mash.new,
25
26
  :template_mappings => Mash.new,
26
- :test_mappings => Mash.new
27
+ :test_mappings => Mash.new,
28
+ :spec_mappings => Mash.new,
29
+ :spec_clusters => Mash.new
27
30
  ).merge(config)
28
31
  @force_bases = args[:force_bases] || []
29
32
  ensure_state
33
+ make_knife_config_if_required
30
34
  end
31
35
 
32
36
  def ensure_state
33
- store_checksums
34
- write_dna_json
35
- write_solo_rb
36
- run_solo if solo_needed?
37
+ check_bases_and_customs!
38
+ if(solo_needed?)
39
+ store_checksums
40
+ write_dna_json
41
+ write_solo_rb
42
+ run_solo if solo_needed?
43
+ end
44
+ end
45
+
46
+ def check_bases_and_customs!
47
+ if(File.exists?(dna_path))
48
+ dna = Mash.new(JSON.load(File.read(dna_path)))
49
+ %w(bases customs).each do |key|
50
+ if(dna[:vagabond][key])
51
+ dna[:vagabond][key].each do |n, opts|
52
+ options[:force_solo] = true unless Lxc.new(n).exists?
53
+ end
54
+ end
55
+ end
56
+ end
37
57
  end
38
58
 
39
59
  def [](k)
@@ -48,24 +68,33 @@ module Vagabond
48
68
  FileUtils.mkdir_p(store_path)
49
69
  end
50
70
 
51
- def load_existing
71
+ def load_existing(file=nil)
52
72
  if(File.exists?(path = File.join(store_path, 'vagabond.json')))
53
- @config = Mash.new(
54
- JSON.load(
55
- File.read(path)
73
+ if(file)
74
+ file.rewind
75
+ content = file.read
76
+ else
77
+ content = File.read(path)
78
+ end
79
+ if(content.strip.empty?)
80
+ config = Mash.new
81
+ else
82
+ config = Mash.new(
83
+ JSON.load(content)
56
84
  )
57
- )
85
+ end
86
+ @config = Chef::Mixin::DeepMerge.merge(config, @config)
58
87
  else
59
88
  @config = Mash.new
60
89
  end
61
90
  end
62
91
 
63
92
  def store_path
64
- FileUtils.mkdir_p(
65
- File.join(
66
- File.dirname(@vagabondfile.path), '.vagabond'
67
- )
68
- )
93
+ path = File.join(File.dirname(@vagabondfile.store_path), '.vagabond')
94
+ unless(File.directory?(path))
95
+ FileUtils.mkdir_p(path)
96
+ end
97
+ path
69
98
  end
70
99
 
71
100
  def dna_path
@@ -90,9 +119,9 @@ module Vagabond
90
119
  conf[:customs][generated_name(t_name)] = opts
91
120
  config[:template_mappings][t_name] = generated_name(t_name)
92
121
  else
93
- ui.fatal "Invalid base template encountered: #{t}"
122
+ ui.fatal "Invalid base template encountered: #{t_name}"
94
123
  ui.info ui.color(" -> Valid base templates: #{BASE_TEMPLATES.sort.join(', ')}", :red)
95
- exit EXIT_CODES[:invalid_base_template]
124
+ raise VagabondError::InvalidBaseTemplate.new(t_name)
96
125
  end
97
126
  end
98
127
  File.open(dna_path, 'w') do |file|
@@ -156,21 +185,85 @@ module Vagabond
156
185
  end
157
186
 
158
187
  def run_solo
159
- ui.info ui.color('Ensuring expected system state (creating required base containers)', :yellow)
160
- ui.info ui.color(' - This can take a while...', :yellow)
161
- com = "#{options[:sudo]}chef-solo -j #{File.join(store_path, 'dna.json')} -c #{File.join(store_path, 'solo.rb')}"
162
- debug(com)
163
- cmd = Mixlib::ShellOut.new(com, :timeout => 12000, :live_stream => options[:debug])
164
- cmd.run_command
165
- cmd.error!
166
- ui.info ui.color(' -> COMPLETE!', :yellow)
188
+ begin
189
+ ui.info ui.color('Ensuring expected system state (creating required base containers)', :yellow)
190
+ ui.info ui.color(' - This can take a while on first run or new templates...', :yellow)
191
+ com = "#{options[:sudo]}chef-solo -j #{File.join(store_path, 'dna.json')} -c #{File.join(store_path, 'solo.rb')}"
192
+ debug(com)
193
+ cmd = Mixlib::ShellOut.new(com, :timeout => 12000, :live_stream => options[:debug])
194
+ cmd.run_command
195
+ cmd.error!
196
+ ui.info ui.color(' -> COMPLETE!', :yellow)
197
+ rescue => e
198
+ ui.info e.to_s
199
+ FileUtils.rm(solo_path)
200
+ ui.info ui.color(' -> FAILED!', :red, :bold)
201
+ raise VagabondError::HostProvisionFailed.new(e)
202
+ end
203
+ end
204
+
205
+ def config_path
206
+ File.join(store_path, 'vagabond.json')
167
207
  end
168
208
 
169
209
  def save
170
- File.open(File.join(store_path, 'vagabond.json'), 'w') do |file|
171
- file.write(JSON.dump(@config))
210
+ mode = File.exists?(config_path) ? 'r+' : 'w+'
211
+ File.open(config_path, mode) do |file|
212
+ file.flock(File::LOCK_EX)
213
+ file.rewind
214
+ if(sha = file_changed?(file.path))
215
+ @checksums[file.path] = sha
216
+ load_existing(file)
217
+ end
218
+ file.rewind
219
+ file.write(JSON.pretty_generate(@config))
220
+ file.truncate(file.pos)
172
221
  end
173
222
  end
174
223
 
224
+ def knife_config_available?
225
+ if(File.exists?(File.join(store_path, 'knife.rb')))
226
+ false
227
+ else
228
+ cwd = @vagabondfile.directory.split('/')
229
+ found = false
230
+ until(found || cwd.empty?)
231
+ found = File.exists?(File.join(*(cwd + ['.chef/knife.rb'])))
232
+ cwd.pop
233
+ end
234
+ found
235
+ end
236
+ end
237
+
238
+ def file_changed?(path)
239
+ checksum = get_checksum(path)
240
+ checksum unless @checksums[path] == checksum
241
+ end
242
+
243
+ def make_knife_config_if_required(force=false)
244
+ if((@vagabondfile[:local_chef_server] && @vagabondfile[:local_chef_server][:enabled]) || force)
245
+ unless(knife_config_available?)
246
+ store_dir = File.dirname(store_path)
247
+ k_dir = File.join(store_dir, '.chef')
248
+ FileUtils.mkdir_p(k_dir)
249
+ unless(File.exists?(knife = File.join(k_dir, 'knife.rb')))
250
+ File.open(knife, 'w') do |file|
251
+ file.write <<-EOF
252
+ node_name 'dummy'
253
+ client_key File.join(File.dirname(__FILE__), 'client.pem')
254
+ validation_client_name 'dummy-validator'
255
+ validation_key File.join(File.dirname(__FILE__), 'validation.pem')
256
+ cookbook_path ['#{%w(cookbooks site-cookbooks).map{|dir|File.join(@vagabondfile.directory, dir)}.join(',')}']
257
+ EOF
258
+ end
259
+ end
260
+ %w(client.pem validation.pem).each do |name|
261
+ unless(File.exists?(pem = File.join(k_dir, name)))
262
+ %x{openssl genrsa -out #{pem} 2048}
263
+ end
264
+ end
265
+ end
266
+ end
267
+ end
175
268
  end
176
269
  end