vagrant 0.1.4 → 0.2.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/Gemfile +1 -1
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/bin/vagrant-box +1 -2
  5. data/bin/vagrant-down +1 -2
  6. data/bin/vagrant-halt +1 -2
  7. data/bin/vagrant-init +1 -2
  8. data/bin/vagrant-package +1 -2
  9. data/bin/vagrant-reload +1 -2
  10. data/bin/vagrant-resume +1 -2
  11. data/bin/vagrant-ssh +1 -2
  12. data/bin/vagrant-status +29 -0
  13. data/bin/vagrant-suspend +1 -2
  14. data/bin/vagrant-up +1 -2
  15. data/config/default.rb +5 -9
  16. data/keys/README.md +10 -0
  17. data/keys/vagrant +27 -0
  18. data/keys/vagrant.pub +1 -0
  19. data/lib/vagrant/actions/base.rb +14 -0
  20. data/lib/vagrant/actions/collection.rb +36 -0
  21. data/lib/vagrant/actions/runner.rb +4 -10
  22. data/lib/vagrant/actions/vm/boot.rb +4 -5
  23. data/lib/vagrant/actions/vm/customize.rb +17 -0
  24. data/lib/vagrant/actions/vm/destroy.rb +11 -2
  25. data/lib/vagrant/actions/vm/forward_ports.rb +24 -0
  26. data/lib/vagrant/actions/vm/import.rb +1 -0
  27. data/lib/vagrant/actions/vm/provision.rb +30 -52
  28. data/lib/vagrant/actions/vm/reload.rb +2 -2
  29. data/lib/vagrant/actions/vm/shared_folders.rb +37 -25
  30. data/lib/vagrant/actions/vm/up.rb +8 -4
  31. data/lib/vagrant/active_list.rb +66 -0
  32. data/lib/vagrant/commands.rb +44 -0
  33. data/lib/vagrant/config.rb +64 -47
  34. data/lib/vagrant/downloaders/file.rb +2 -12
  35. data/lib/vagrant/env.rb +48 -12
  36. data/lib/vagrant/provisioners/base.rb +22 -0
  37. data/lib/vagrant/provisioners/chef.rb +102 -0
  38. data/lib/vagrant/provisioners/chef_server.rb +96 -0
  39. data/lib/vagrant/provisioners/chef_solo.rb +67 -0
  40. data/lib/vagrant/ssh.rb +25 -6
  41. data/lib/vagrant/stacked_proc_runner.rb +33 -0
  42. data/lib/vagrant/vm.rb +8 -0
  43. data/lib/vagrant.rb +10 -5
  44. data/test/test_helper.rb +22 -6
  45. data/test/vagrant/actions/collection_test.rb +110 -0
  46. data/test/vagrant/actions/runner_test.rb +11 -7
  47. data/test/vagrant/actions/vm/boot_test.rb +7 -7
  48. data/test/vagrant/actions/vm/customize_test.rb +16 -0
  49. data/test/vagrant/actions/vm/destroy_test.rb +19 -6
  50. data/test/vagrant/actions/vm/forward_ports_test.rb +52 -0
  51. data/test/vagrant/actions/vm/import_test.rb +10 -3
  52. data/test/vagrant/actions/vm/provision_test.rb +75 -70
  53. data/test/vagrant/actions/vm/reload_test.rb +3 -2
  54. data/test/vagrant/actions/vm/shared_folders_test.rb +62 -9
  55. data/test/vagrant/actions/vm/up_test.rb +4 -4
  56. data/test/vagrant/active_list_test.rb +169 -0
  57. data/test/vagrant/config_test.rb +145 -29
  58. data/test/vagrant/downloaders/file_test.rb +4 -19
  59. data/test/vagrant/env_test.rb +96 -23
  60. data/test/vagrant/provisioners/base_test.rb +27 -0
  61. data/test/vagrant/provisioners/chef_server_test.rb +175 -0
  62. data/test/vagrant/provisioners/chef_solo_test.rb +142 -0
  63. data/test/vagrant/provisioners/chef_test.rb +116 -0
  64. data/test/vagrant/ssh_test.rb +29 -8
  65. data/test/vagrant/stacked_proc_runner_test.rb +43 -0
  66. data/test/vagrant/vm_test.rb +23 -0
  67. data/vagrant.gemspec +35 -8
  68. metadata +42 -11
  69. data/script/vagrant-ssh-expect.sh +0 -22
@@ -11,13 +11,17 @@ virtual machine already exists and is not a file! The dotfile is
11
11
  currently configured to be `#{Env.dotfile_path}`
12
12
 
13
13
  To change this value, please see `config.vagrant.dotfile_name`
14
+
15
+ This often exists if you're trying to create a Vagrant virtual
16
+ environment from your home directory. To resolve this, you can either
17
+ modify the configuration a bit, or simply use a different directory.
14
18
  msg
15
19
  end
16
20
 
17
21
  # Up is a "meta-action" so it really just queues up a bunch
18
22
  # of other actions in its place:
19
- steps = [Import, ForwardPorts, SharedFolders, Boot]
20
- steps << Provision if Vagrant.config.chef.enabled
23
+ steps = [Import, Customize, ForwardPorts, SharedFolders, Boot]
24
+ steps << Provision if !Vagrant.config.vm.provisioner.nil?
21
25
  steps.insert(0, MoveHardDrive) if Vagrant.config.vm.hd_location
22
26
 
23
27
  steps.each do |action_klass|
@@ -31,8 +35,8 @@ msg
31
35
  end
32
36
 
33
37
  def persist
34
- logger.info "Persisting the VM UUID (#{@runner.vm.uuid})..."
35
- Env.persist_vm(@runner.vm)
38
+ logger.info "Persisting the VM UUID (#{@runner.uuid})..."
39
+ Env.persist_vm(@runner)
36
40
  end
37
41
 
38
42
  def setup_mac_address
@@ -0,0 +1,66 @@
1
+ module Vagrant
2
+ # This class represents the active list of vagrant virtual
3
+ # machines.
4
+ class ActiveList
5
+ FILENAME = "active.json"
6
+
7
+ @@list = nil
8
+
9
+ class <<self
10
+ # Parses and returns the list of UUIDs from the active VM
11
+ # JSON file. This will cache the result, which can be reloaded
12
+ # by setting the `reload` parameter to true.
13
+ #
14
+ # @return [Array<String>]
15
+ def list(reload = false)
16
+ return @@list unless @@list.nil? || reload
17
+
18
+ @@list ||= []
19
+ return @@list unless File.file?(path)
20
+ File.open(path, "r") do |f|
21
+ @@list = JSON.parse(f.read)
22
+ end
23
+
24
+ @@list
25
+ end
26
+
27
+ # Returns an array of {Vagrant::VM} objects which are currently
28
+ # active.
29
+ def vms
30
+ list.collect { |uuid| Vagrant::VM.find(uuid) }.compact
31
+ end
32
+
33
+ # Returns an array of UUIDs filtered so each is verified to exist.
34
+ def filtered_list
35
+ vms.collect { |vm| vm.uuid }
36
+ end
37
+
38
+ # Adds a virtual environment to the list of active virtual machines
39
+ def add(vm)
40
+ list << vm.uuid
41
+ list.uniq!
42
+ save
43
+ end
44
+
45
+ # Remove a virtual environment from the list of active virtual machines
46
+ def remove(vm)
47
+ vm = vm.uuid if vm.is_a?(Vagrant::VM)
48
+ list.delete(vm)
49
+ save
50
+ end
51
+
52
+ # Persists the list down to the JSON file.
53
+ def save
54
+ File.open(path, "w+") do |f|
55
+ f.write(filtered_list.to_json)
56
+ end
57
+ end
58
+
59
+ # Returns the path to the JSON file which holds the UUIDs of the
60
+ # active virtual machines managed by Vagrant.
61
+ def path
62
+ File.join(Env.home_path, FILENAME)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -24,6 +24,49 @@ error
24
24
  FileUtils.cp(File.join(PROJECT_ROOT, "templates", Env::ROOTFILE_NAME), rootfile_path)
25
25
  end
26
26
 
27
+ # Outputs the status of the current environment. This command outputs
28
+ # useful information such as whether or not the environment is created
29
+ # and if its running, suspended, etc.
30
+ def status
31
+ Env.load!
32
+
33
+ wrap_output do
34
+ if !Env.persisted_vm
35
+ puts <<-msg
36
+ The environment has not yet been created. Run `vagrant up` to create the
37
+ environment.
38
+ msg
39
+ else
40
+ additional_msg = ""
41
+ if Env.persisted_vm.vm.running?
42
+ additional_msg = <<-msg
43
+ To stop this VM, you can run `vagrant halt` to shut it down forcefully,
44
+ or you can run `vagrant suspend` to simply suspend the virtual machine.
45
+ In either case, to restart it again, simply run a `vagrant up`.
46
+ msg
47
+ elsif Env.persisted_vm.vm.saved?
48
+ additional_msg = <<-msg
49
+ To resume this VM, simply run `vagrant up`.
50
+ msg
51
+ elsif Env.persisted_vm.vm.powered_off?
52
+ additional_msg = <<-msg
53
+ To restart this VM, simply run `vagrant up`.
54
+ msg
55
+ end
56
+
57
+ if !additional_msg.empty?
58
+ additional_msg.chomp!
59
+ additional_msg = "\n\n#{additional_msg}"
60
+ end
61
+
62
+ puts <<-msg
63
+ The environment has been created. The status of the current environment's
64
+ virtual machine is: "#{Env.persisted_vm.vm.state}."#{additional_msg}
65
+ msg
66
+ end
67
+ end
68
+ end
69
+
27
70
  # Bring up a vagrant instance. This handles everything from importing
28
71
  # the base VM, setting up shared folders, forwarded ports, etc to
29
72
  # provisioning the instance with chef. {up} also starts the instance,
@@ -139,6 +182,7 @@ Please specify a valid action to take on the boxes, either
139
182
 
140
183
  vagrant box add name uri
141
184
  vagrant box remove name
185
+ vagrant box list
142
186
  error
143
187
  end
144
188
 
@@ -4,32 +4,30 @@ module Vagrant
4
4
  end
5
5
 
6
6
  class Config
7
- @config = nil
8
- @config_runners = []
7
+ extend StackedProcRunner
8
+
9
+ @@config = nil
9
10
 
10
11
  class << self
11
12
  def reset!
12
- @config = nil
13
- config_runners.clear
13
+ @@config = nil
14
+ proc_stack.clear
14
15
  end
15
16
 
16
- def config
17
- @config ||= Config::Top.new
17
+ def configures(key, klass)
18
+ config.class.configures(key, klass)
18
19
  end
19
20
 
20
- def config_runners
21
- @config_runners ||= []
21
+ def config
22
+ @@config ||= Config::Top.new
22
23
  end
23
24
 
24
25
  def run(&block)
25
- config_runners << block
26
+ push_proc(&block)
26
27
  end
27
28
 
28
29
  def execute!
29
- config_runners.each do |block|
30
- block.call(config)
31
- end
32
-
30
+ run_procs!(config)
33
31
  config.loaded!
34
32
  end
35
33
  end
@@ -60,20 +58,32 @@ module Vagrant
60
58
  attr_accessor :forwarded_port_key
61
59
  attr_accessor :max_tries
62
60
  attr_accessor :timeout
61
+ attr_accessor :private_key_path
62
+
63
+ def private_key_path
64
+ File.expand_path(@private_key_path, Env.root_path)
65
+ end
63
66
  end
64
67
 
65
68
  class VMConfig < Base
69
+ include StackedProcRunner
70
+
66
71
  attr_accessor :box
67
72
  attr_accessor :box_ovf
68
73
  attr_accessor :base_mac
69
74
  attr_accessor :project_directory
70
75
  attr_reader :forwarded_ports
76
+ attr_reader :shared_folders
71
77
  attr_accessor :hd_location
72
78
  attr_accessor :disk_image_format
73
-
79
+ attr_accessor :provisioner
80
+ attr_accessor :shared_folder_uid
81
+ attr_accessor :shared_folder_gid
74
82
 
75
83
  def initialize
76
84
  @forwarded_ports = {}
85
+ @shared_folders = {}
86
+ @provisioner = nil
77
87
  end
78
88
 
79
89
  def forward_port(name, guestport, hostport, protocol="TCP")
@@ -84,13 +94,28 @@ module Vagrant
84
94
  }
85
95
  end
86
96
 
97
+ def share_folder(name, guestpath, hostpath)
98
+ @shared_folders[name] = {
99
+ :guestpath => guestpath,
100
+ :hostpath => hostpath
101
+ }
102
+ end
103
+
87
104
  def hd_location=(val)
88
- raise Exception.new "disk_storage must be set to a directory" unless File.directory?(val)
105
+ raise Exception.new("disk_storage must be set to a directory") unless File.directory?(val)
89
106
  @hd_location=val
90
107
  end
91
108
 
92
- def base
93
- File.expand_path(@base)
109
+ def shared_folder_uid
110
+ @shared_folder_uid || Vagrant.config.ssh.username
111
+ end
112
+
113
+ def shared_folder_gid
114
+ @shared_folder_gid || Vagrant.config.ssh.username
115
+ end
116
+
117
+ def customize(&block)
118
+ push_proc(&block)
94
119
  end
95
120
  end
96
121
 
@@ -99,48 +124,40 @@ module Vagrant
99
124
  attr_accessor :extension
100
125
  end
101
126
 
102
- class ChefConfig < Base
103
- attr_accessor :cookbooks_path
104
- attr_accessor :provisioning_path
105
- attr_accessor :json
106
- attr_accessor :enabled
107
-
108
- def initialize
109
- @enabled = false
110
- end
111
-
112
- def to_json
113
- # Overridden so that the 'json' key could be removed, since its just
114
- # merged into the config anyways
115
- data = instance_variables_hash
116
- data.delete(:json)
117
- data.to_json
118
- end
119
- end
120
-
121
127
  class VagrantConfig < Base
122
128
  attr_accessor :dotfile_name
123
129
  attr_accessor :log_output
124
130
  attr_accessor :home
125
131
 
126
132
  def home
127
- File.expand_path(@home)
133
+ @home ? File.expand_path(@home) : nil
128
134
  end
129
135
  end
130
136
 
131
137
  class Top < Base
132
- attr_reader :package
133
- attr_reader :ssh
134
- attr_reader :vm
135
- attr_reader :chef
136
- attr_reader :vagrant
138
+ @@configures = []
139
+
140
+ class <<self
141
+ def configures_list
142
+ @@configures ||= []
143
+ end
144
+
145
+ def configures(key, klass)
146
+ configures_list << [key, klass]
147
+ attr_reader key.to_sym
148
+ end
149
+ end
150
+
151
+ # Setup default configures
152
+ configures :package, PackageConfig
153
+ configures :ssh, SSHConfig
154
+ configures :vm, VMConfig
155
+ configures :vagrant, VagrantConfig
137
156
 
138
157
  def initialize
139
- @ssh = SSHConfig.new
140
- @vm = VMConfig.new
141
- @chef = ChefConfig.new
142
- @vagrant = VagrantConfig.new
143
- @package = PackageConfig.new
158
+ self.class.configures_list.each do |key, klass|
159
+ instance_variable_set("@#{key}".to_sym, klass.new)
160
+ end
144
161
 
145
162
  @loaded = false
146
163
  end
@@ -3,19 +3,9 @@ module Vagrant
3
3
  # "Downloads" a file to a temporary file. Basically, this downloader
4
4
  # simply does a file copy.
5
5
  class File < Base
6
- BUFFERSIZE = 1048576 # 1 MB
7
-
8
6
  def download!(source_url, destination_file)
9
- # For now we read the contents of one into a buffer
10
- # and copy it into the other. In the future, we should do
11
- # a system-level file copy (FileUtils.cp).
12
- open(source_url) do |f|
13
- loop do
14
- break if f.eof?
15
- destination_file.write(f.read(BUFFERSIZE))
16
- end
17
- end
7
+ FileUtils.cp(source_url, destination_file.path)
18
8
  end
19
9
  end
20
10
  end
21
- end
11
+ end
data/lib/vagrant/env.rb CHANGED
@@ -24,21 +24,52 @@ module Vagrant
24
24
  load_config!
25
25
  load_home_directory!
26
26
  load_box!
27
+ load_config!
28
+ check_virtualbox!
27
29
  load_vm!
28
30
  end
29
31
 
32
+ def check_virtualbox!
33
+ version = VirtualBox::Command.version
34
+ if version.nil?
35
+ error_and_exit(<<-msg)
36
+ Vagrant could not detect VirtualBox! Make sure VirtualBox is properly installed.
37
+ If VirtualBox is installed, you may need to tweak the paths to the `VBoxManage`
38
+ application which ships with VirtualBox and the path to the global XML configuration
39
+ which VirtualBox typically stores somewhere in your home directory.
40
+
41
+ The following shows how to configure VirtualBox. This can be done in the
42
+ Vagrantfile. Note that 90% of the time, you shouldn't need to do this if VirtualBox
43
+ is installed. Please use the various Vagrant support lines to request more information
44
+ if you can't get this working.
45
+
46
+ VirtualBox::Command.vboxmanage = "/path/to/my/VBoxManage"
47
+ VirtualBox::Global.vboxconfig = "~/path/to/VirtualBox.xml"
48
+ msg
49
+ elsif version.to_f < 3.1
50
+ error_and_exit(<<-msg)
51
+ Vagrant has detected that you have VirtualBox version #{version} installed!
52
+ Vagrant requires that you use at least VirtualBox version 3.1. Please install
53
+ a more recent version of VirtualBox to continue.
54
+ msg
55
+ end
56
+ end
57
+
30
58
  def load_config!
31
59
  # Prepare load paths for config files
32
60
  load_paths = [File.join(PROJECT_ROOT, "config", "default.rb")]
33
61
  load_paths << File.join(box.directory, ROOTFILE_NAME) if box
62
+ load_paths << File.join(home_path, ROOTFILE_NAME) if Vagrant.config.vagrant.home
34
63
  load_paths << File.join(root_path, ROOTFILE_NAME) if root_path
35
64
 
36
65
  # Then clear out the old data
37
66
  Config.reset!
38
67
 
39
68
  load_paths.each do |path|
40
- logger.info "Loading config from #{path}..."
41
- load path if File.exist?(path)
69
+ if File.exist?(path)
70
+ logger.info "Loading config from #{path}..."
71
+ load path
72
+ end
42
73
  end
43
74
 
44
75
  # Execute the configurations
@@ -63,11 +94,6 @@ module Vagrant
63
94
  return unless root_path
64
95
 
65
96
  @@box = Box.find(Vagrant.config.vm.box) if Vagrant.config.vm.box
66
-
67
- if @@box
68
- logger.info("Reloading configuration to account for loaded box...")
69
- load_config!
70
- end
71
97
  end
72
98
 
73
99
  def load_vm!
@@ -81,18 +107,28 @@ module Vagrant
81
107
  end
82
108
 
83
109
  def persist_vm(vm)
110
+ # Save to the dotfile for this project
84
111
  File.open(dotfile_path, 'w+') do |f|
85
112
  f.write(vm.uuid)
86
113
  end
114
+
115
+ # Also add to the global store
116
+ ActiveList.add(vm)
117
+ end
118
+
119
+ def depersist_vm(vm)
120
+ # Delete the dotfile if it exists
121
+ File.delete(dotfile_path) if File.exist?(dotfile_path)
122
+
123
+ # Remove from the global store
124
+ ActiveList.remove(vm)
87
125
  end
88
126
 
89
127
  def load_root_path!(path=nil)
90
- path ||= Pathname.new(Dir.pwd)
128
+ path = Pathname.new(File.expand_path(path || Dir.pwd))
91
129
 
92
- # Stop if we're at the root. 2nd regex matches windows drives
93
- # such as C:. and Z:. Portability of this check will need to be
94
- # researched.
95
- return false if path.to_s == '/' || path.to_s =~ /^[A-Z]:\.$/
130
+ # Stop if we're at the root.
131
+ return false if path.root?
96
132
 
97
133
  file = "#{path}/#{ROOTFILE_NAME}"
98
134
  if File.exist?(file)
@@ -0,0 +1,22 @@
1
+ module Vagrant
2
+ module Provisioners
3
+ # The base class for a "provisioner." A provisioner is responsible for
4
+ # provisioning a Vagrant system. This has been abstracted out to provide
5
+ # support for multiple solutions such as Chef Solo, Chef Client, and
6
+ # Puppet.
7
+ class Base
8
+ include Vagrant::Util
9
+
10
+ # This is the method called to "prepare" the provisioner. This is called
11
+ # before any actions are run by the action runner (see {Vagrant::Actions::Runner}).
12
+ # This can be used to setup shared folders, forward ports, etc. Whatever is
13
+ # necessary on a "meta" level.
14
+ def prepare; end
15
+
16
+ # This is the method called to provision the system. This method
17
+ # is expected to do whatever necessary to provision the system (create files,
18
+ # SSH, etc.)
19
+ def provision!; end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,102 @@
1
+ module Vagrant
2
+ module Provisioners
3
+ # This class is a base class where the common functinality shared between
4
+ # chef-solo and chef-client provisioning are stored. This is **not an actual
5
+ # provisioner**. Instead, {ChefSolo} or {ChefServer} should be used.
6
+ class Chef < Base
7
+ # This is the configuration which is available through `config.chef`
8
+ class ChefConfig < Vagrant::Config::Base
9
+ # Chef server specific config
10
+ attr_accessor :chef_server_url
11
+ attr_accessor :validation_key_path
12
+ attr_accessor :validation_client_name
13
+ attr_accessor :client_key_path
14
+
15
+ # Chef solo specific config
16
+ attr_accessor :cookbooks_path
17
+
18
+ # Shared config
19
+ attr_accessor :provisioning_path
20
+ attr_accessor :json
21
+
22
+ def initialize
23
+ @validation_client_name = "chef-validator"
24
+ @client_key_path = "/etc/chef/client.pem"
25
+
26
+ @cookbooks_path = "cookbooks"
27
+ @provisioning_path = "/tmp/vagrant-chef"
28
+ @json = {
29
+ :instance_role => "vagrant",
30
+ :run_list => ["recipe[vagrant_main]"]
31
+ }
32
+ end
33
+
34
+ # Returns the run list for the provisioning
35
+ def run_list
36
+ json[:run_list]
37
+ end
38
+
39
+ # Sets the run list to the specified value
40
+ def run_list=(value)
41
+ json[:run_list] = value
42
+ end
43
+
44
+ # Adds a recipe to the run list
45
+ def add_recipe(name)
46
+ name = "recipe[#{name}]" unless name =~ /^recipe\[(.+?)\]$/
47
+ run_list << name
48
+ end
49
+
50
+ # Adds a role to the run list
51
+ def add_role(name)
52
+ name = "role[#{name}]" unless name =~ /^role\[(.+?)\]$/
53
+ run_list << name
54
+ end
55
+
56
+ def to_json
57
+ # Overridden so that the 'json' key could be removed, since its just
58
+ # merged into the config anyways
59
+ data = instance_variables_hash
60
+ data.delete(:json)
61
+ data.to_json
62
+ end
63
+ end
64
+
65
+ # Tell the Vagrant configure class about our custom configuration
66
+ Config.configures :chef, ChefConfig
67
+
68
+ def prepare
69
+ raise Actions::ActionException.new("Vagrant::Provisioners::Chef is not a valid provisioner! Use ChefSolo or ChefServer instead.")
70
+ end
71
+
72
+ def chown_provisioning_folder
73
+ logger.info "Setting permissions on chef provisioning folder..."
74
+ SSH.execute do |ssh|
75
+ ssh.exec!("sudo mkdir -p #{Vagrant.config.chef.provisioning_path}")
76
+ ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
77
+ end
78
+ end
79
+
80
+ def setup_json
81
+ logger.info "Generating chef JSON and uploading..."
82
+
83
+ # Set up initial configuration
84
+ data = {
85
+ :config => Vagrant.config,
86
+ :directory => Vagrant.config.vm.project_directory,
87
+ }
88
+
89
+ # And wrap it under the "vagrant" namespace
90
+ data = { :vagrant => data }
91
+
92
+ # Merge with the "extra data" which isn't put under the
93
+ # vagrant namespace by default
94
+ data.merge!(Vagrant.config.chef.json)
95
+
96
+ json = data.to_json
97
+
98
+ SSH.upload!(StringIO.new(json), File.join(Vagrant.config.chef.provisioning_path, "dna.json"))
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,96 @@
1
+ module Vagrant
2
+ module Provisioners
3
+ # This class implements provisioning via chef-client, allowing provisioning
4
+ # with a chef server.
5
+ class ChefServer < Chef
6
+ def prepare
7
+ if Vagrant.config.chef.validation_key_path.nil?
8
+ raise Actions::ActionException.new(<<-msg)
9
+ Chef server provisioning requires that the `config.chef.validation_key_path` configuration
10
+ be set to a path on your local machine of the validation key used to register the
11
+ VM with the chef server.
12
+ msg
13
+ elsif !File.file?(Vagrant.config.chef.validation_key_path)
14
+ raise Actions::ActionException.new(<<-msg)
15
+ The validation key set for `config.chef.validation_key_path` does not exist! This
16
+ file needs to exist so it can be uploaded to the virtual machine. It is
17
+ currently set to "#{Vagrant.config.chef.validation_key_path}"
18
+ msg
19
+ end
20
+
21
+ if Vagrant.config.chef.chef_server_url.nil?
22
+ raise Actions::ActionException.new(<<-msg)
23
+ Chef server provisioning requires that the `config.chef.chef_server_url` be set to the
24
+ URL of your chef server. Examples include "http://12.12.12.12:4000" and
25
+ "http://myserver.com:4000" (the port of course can be different, but 4000 is the default)
26
+ msg
27
+ end
28
+ end
29
+
30
+ def provision!
31
+ chown_provisioning_folder
32
+ create_client_key_folder
33
+ upload_validation_key
34
+ setup_json
35
+ setup_config
36
+ run_chef_client
37
+ end
38
+
39
+ def create_client_key_folder
40
+ logger.info "Creating folder to hold client key..."
41
+ path = Pathname.new(Vagrant.config.chef.client_key_path)
42
+
43
+ SSH.execute do |ssh|
44
+ ssh.exec!("sudo mkdir -p #{path.dirname}")
45
+ end
46
+ end
47
+
48
+ def upload_validation_key
49
+ logger.info "Uploading chef client validation key..."
50
+ SSH.upload!(validation_key_path, guest_validation_key_path)
51
+ end
52
+
53
+ def setup_config
54
+ solo_file = <<-solo
55
+ log_level :info
56
+ log_location STDOUT
57
+ ssl_verify_mode :verify_none
58
+ chef_server_url "#{Vagrant.config.chef.chef_server_url}"
59
+
60
+ validation_client_name "#{Vagrant.config.chef.validation_client_name}"
61
+ validation_key "#{guest_validation_key_path}"
62
+ client_key "#{Vagrant.config.chef.client_key_path}"
63
+
64
+ file_store_path "/srv/chef/file_store"
65
+ file_cache_path "/srv/chef/cache"
66
+
67
+ pid_file "/var/run/chef/chef-client.pid"
68
+
69
+ Mixlib::Log::Formatter.show_time = true
70
+ solo
71
+
72
+ logger.info "Uploading chef-client configuration script..."
73
+ SSH.upload!(StringIO.new(solo_file), File.join(Vagrant.config.chef.provisioning_path, "client.rb"))
74
+ end
75
+
76
+ def run_chef_client
77
+ logger.info "Running chef-client..."
78
+ SSH.execute do |ssh|
79
+ ssh.exec!("cd #{Vagrant.config.chef.provisioning_path} && sudo chef-client -c client.rb -j dna.json") do |channel, data, stream|
80
+ # TODO: Very verbose. It would be easier to save the data and only show it during
81
+ # an error, or when verbosity level is set high
82
+ logger.info("#{stream}: #{data}")
83
+ end
84
+ end
85
+ end
86
+
87
+ def validation_key_path
88
+ File.expand_path(Vagrant.config.chef.validation_key_path, Env.root_path)
89
+ end
90
+
91
+ def guest_validation_key_path
92
+ File.join(Vagrant.config.chef.provisioning_path, "validation.pem")
93
+ end
94
+ end
95
+ end
96
+ end