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.
- 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
|