vagrant 0.1.4 → 0.2.0.pre
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.
- data/Gemfile +1 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/bin/vagrant-box +1 -2
- data/bin/vagrant-down +1 -2
- data/bin/vagrant-halt +1 -2
- data/bin/vagrant-init +1 -2
- data/bin/vagrant-package +1 -2
- data/bin/vagrant-reload +1 -2
- data/bin/vagrant-resume +1 -2
- data/bin/vagrant-ssh +1 -2
- data/bin/vagrant-status +29 -0
- data/bin/vagrant-suspend +1 -2
- data/bin/vagrant-up +1 -2
- data/config/default.rb +5 -9
- data/keys/README.md +10 -0
- data/keys/vagrant +27 -0
- data/keys/vagrant.pub +1 -0
- data/lib/vagrant/actions/base.rb +14 -0
- data/lib/vagrant/actions/collection.rb +36 -0
- data/lib/vagrant/actions/runner.rb +4 -10
- data/lib/vagrant/actions/vm/boot.rb +4 -5
- data/lib/vagrant/actions/vm/customize.rb +17 -0
- data/lib/vagrant/actions/vm/destroy.rb +11 -2
- data/lib/vagrant/actions/vm/forward_ports.rb +24 -0
- data/lib/vagrant/actions/vm/import.rb +1 -0
- data/lib/vagrant/actions/vm/provision.rb +30 -52
- data/lib/vagrant/actions/vm/reload.rb +2 -2
- data/lib/vagrant/actions/vm/shared_folders.rb +37 -25
- data/lib/vagrant/actions/vm/up.rb +8 -4
- data/lib/vagrant/active_list.rb +66 -0
- data/lib/vagrant/commands.rb +44 -0
- data/lib/vagrant/config.rb +64 -47
- data/lib/vagrant/downloaders/file.rb +2 -12
- data/lib/vagrant/env.rb +48 -12
- data/lib/vagrant/provisioners/base.rb +22 -0
- data/lib/vagrant/provisioners/chef.rb +102 -0
- data/lib/vagrant/provisioners/chef_server.rb +96 -0
- data/lib/vagrant/provisioners/chef_solo.rb +67 -0
- data/lib/vagrant/ssh.rb +25 -6
- data/lib/vagrant/stacked_proc_runner.rb +33 -0
- data/lib/vagrant/vm.rb +8 -0
- data/lib/vagrant.rb +10 -5
- data/test/test_helper.rb +22 -6
- data/test/vagrant/actions/collection_test.rb +110 -0
- data/test/vagrant/actions/runner_test.rb +11 -7
- data/test/vagrant/actions/vm/boot_test.rb +7 -7
- data/test/vagrant/actions/vm/customize_test.rb +16 -0
- data/test/vagrant/actions/vm/destroy_test.rb +19 -6
- data/test/vagrant/actions/vm/forward_ports_test.rb +52 -0
- data/test/vagrant/actions/vm/import_test.rb +10 -3
- data/test/vagrant/actions/vm/provision_test.rb +75 -70
- data/test/vagrant/actions/vm/reload_test.rb +3 -2
- data/test/vagrant/actions/vm/shared_folders_test.rb +62 -9
- data/test/vagrant/actions/vm/up_test.rb +4 -4
- data/test/vagrant/active_list_test.rb +169 -0
- data/test/vagrant/config_test.rb +145 -29
- data/test/vagrant/downloaders/file_test.rb +4 -19
- data/test/vagrant/env_test.rb +96 -23
- data/test/vagrant/provisioners/base_test.rb +27 -0
- data/test/vagrant/provisioners/chef_server_test.rb +175 -0
- data/test/vagrant/provisioners/chef_solo_test.rb +142 -0
- data/test/vagrant/provisioners/chef_test.rb +116 -0
- data/test/vagrant/ssh_test.rb +29 -8
- data/test/vagrant/stacked_proc_runner_test.rb +43 -0
- data/test/vagrant/vm_test.rb +23 -0
- data/vagrant.gemspec +35 -8
- metadata +42 -11
- 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.
|
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.
|
35
|
-
Env.persist_vm(@runner
|
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
|
data/lib/vagrant/commands.rb
CHANGED
@@ -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
|
|
data/lib/vagrant/config.rb
CHANGED
@@ -4,32 +4,30 @@ module Vagrant
|
|
4
4
|
end
|
5
5
|
|
6
6
|
class Config
|
7
|
-
|
8
|
-
|
7
|
+
extend StackedProcRunner
|
8
|
+
|
9
|
+
@@config = nil
|
9
10
|
|
10
11
|
class << self
|
11
12
|
def reset!
|
12
|
-
|
13
|
-
|
13
|
+
@@config = nil
|
14
|
+
proc_stack.clear
|
14
15
|
end
|
15
16
|
|
16
|
-
def
|
17
|
-
|
17
|
+
def configures(key, klass)
|
18
|
+
config.class.configures(key, klass)
|
18
19
|
end
|
19
20
|
|
20
|
-
def
|
21
|
-
|
21
|
+
def config
|
22
|
+
@@config ||= Config::Top.new
|
22
23
|
end
|
23
24
|
|
24
25
|
def run(&block)
|
25
|
-
|
26
|
+
push_proc(&block)
|
26
27
|
end
|
27
28
|
|
28
29
|
def execute!
|
29
|
-
|
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
|
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
|
93
|
-
|
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
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
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
|
-
|
140
|
-
|
141
|
-
|
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
|
-
|
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
|
-
|
41
|
-
|
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
|
128
|
+
path = Pathname.new(File.expand_path(path || Dir.pwd))
|
91
129
|
|
92
|
-
# Stop if we're at the root.
|
93
|
-
|
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
|