vagrant 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +11 -0
- data/Gemfile +17 -0
- data/README.md +45 -0
- data/Rakefile +41 -0
- data/VERSION +1 -0
- data/bin/.gitignore +0 -0
- data/bin/vagrant +15 -0
- data/bin/vagrant-box +35 -0
- data/bin/vagrant-down +28 -0
- data/bin/vagrant-halt +29 -0
- data/bin/vagrant-init +28 -0
- data/bin/vagrant-package +30 -0
- data/bin/vagrant-reload +30 -0
- data/bin/vagrant-resume +28 -0
- data/bin/vagrant-ssh +28 -0
- data/bin/vagrant-suspend +28 -0
- data/bin/vagrant-up +30 -0
- data/config/default.rb +29 -0
- data/lib/vagrant.rb +14 -0
- data/lib/vagrant/actions/base.rb +93 -0
- data/lib/vagrant/actions/box/add.rb +22 -0
- data/lib/vagrant/actions/box/destroy.rb +14 -0
- data/lib/vagrant/actions/box/download.rb +63 -0
- data/lib/vagrant/actions/box/unpackage.rb +49 -0
- data/lib/vagrant/actions/runner.rb +128 -0
- data/lib/vagrant/actions/vm/destroy.rb +14 -0
- data/lib/vagrant/actions/vm/down.rb +12 -0
- data/lib/vagrant/actions/vm/export.rb +41 -0
- data/lib/vagrant/actions/vm/forward_ports.rb +32 -0
- data/lib/vagrant/actions/vm/halt.rb +14 -0
- data/lib/vagrant/actions/vm/import.rb +17 -0
- data/lib/vagrant/actions/vm/move_hard_drive.rb +53 -0
- data/lib/vagrant/actions/vm/package.rb +61 -0
- data/lib/vagrant/actions/vm/provision.rb +71 -0
- data/lib/vagrant/actions/vm/reload.rb +17 -0
- data/lib/vagrant/actions/vm/resume.rb +16 -0
- data/lib/vagrant/actions/vm/shared_folders.rb +69 -0
- data/lib/vagrant/actions/vm/start.rb +50 -0
- data/lib/vagrant/actions/vm/suspend.rb +16 -0
- data/lib/vagrant/actions/vm/up.rb +35 -0
- data/lib/vagrant/box.rb +129 -0
- data/lib/vagrant/busy.rb +73 -0
- data/lib/vagrant/commands.rb +174 -0
- data/lib/vagrant/config.rb +156 -0
- data/lib/vagrant/downloaders/base.rb +13 -0
- data/lib/vagrant/downloaders/file.rb +21 -0
- data/lib/vagrant/downloaders/http.rb +47 -0
- data/lib/vagrant/env.rb +140 -0
- data/lib/vagrant/ssh.rb +43 -0
- data/lib/vagrant/util.rb +45 -0
- data/lib/vagrant/vm.rb +57 -0
- data/script/vagrant-ssh-expect.sh +22 -0
- data/templates/Vagrantfile +8 -0
- data/test/test_helper.rb +91 -0
- data/test/vagrant/actions/base_test.rb +32 -0
- data/test/vagrant/actions/box/add_test.rb +37 -0
- data/test/vagrant/actions/box/destroy_test.rb +18 -0
- data/test/vagrant/actions/box/download_test.rb +118 -0
- data/test/vagrant/actions/box/unpackage_test.rb +101 -0
- data/test/vagrant/actions/runner_test.rb +236 -0
- data/test/vagrant/actions/vm/destroy_test.rb +24 -0
- data/test/vagrant/actions/vm/down_test.rb +32 -0
- data/test/vagrant/actions/vm/export_test.rb +88 -0
- data/test/vagrant/actions/vm/forward_ports_test.rb +50 -0
- data/test/vagrant/actions/vm/halt_test.rb +27 -0
- data/test/vagrant/actions/vm/import_test.rb +36 -0
- data/test/vagrant/actions/vm/move_hard_drive_test.rb +108 -0
- data/test/vagrant/actions/vm/package_test.rb +155 -0
- data/test/vagrant/actions/vm/provision_test.rb +103 -0
- data/test/vagrant/actions/vm/reload_test.rb +44 -0
- data/test/vagrant/actions/vm/resume_test.rb +27 -0
- data/test/vagrant/actions/vm/shared_folders_test.rb +117 -0
- data/test/vagrant/actions/vm/start_test.rb +55 -0
- data/test/vagrant/actions/vm/suspend_test.rb +27 -0
- data/test/vagrant/actions/vm/up_test.rb +76 -0
- data/test/vagrant/box_test.rb +92 -0
- data/test/vagrant/busy_test.rb +81 -0
- data/test/vagrant/commands_test.rb +252 -0
- data/test/vagrant/config_test.rb +123 -0
- data/test/vagrant/downloaders/base_test.rb +20 -0
- data/test/vagrant/downloaders/file_test.rb +32 -0
- data/test/vagrant/downloaders/http_test.rb +40 -0
- data/test/vagrant/env_test.rb +293 -0
- data/test/vagrant/ssh_test.rb +95 -0
- data/test/vagrant/util_test.rb +64 -0
- data/test/vagrant/vm_test.rb +96 -0
- metadata +275 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Actions
|
3
|
+
module VM
|
4
|
+
class Export < Base
|
5
|
+
attr_reader :temp_dir
|
6
|
+
|
7
|
+
def execute!
|
8
|
+
setup_temp_dir
|
9
|
+
export
|
10
|
+
end
|
11
|
+
|
12
|
+
def cleanup
|
13
|
+
if temp_dir
|
14
|
+
logger.info "Removing temporary export directory..."
|
15
|
+
FileUtils.rm_r(temp_dir)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def rescue(exception)
|
20
|
+
cleanup
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup_temp_dir
|
24
|
+
@temp_dir = File.join(Env.tmp_path, Time.now.to_i.to_s)
|
25
|
+
|
26
|
+
logger.info "Creating temporary directory for export..."
|
27
|
+
FileUtils.mkpath(temp_dir)
|
28
|
+
end
|
29
|
+
|
30
|
+
def ovf_path
|
31
|
+
File.join(temp_dir, Vagrant.config.vm.box_ovf)
|
32
|
+
end
|
33
|
+
|
34
|
+
def export
|
35
|
+
logger.info "Exporting VM to #{ovf_path} ..."
|
36
|
+
@runner.vm.export(ovf_path, {}, true)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Actions
|
3
|
+
module VM
|
4
|
+
class ForwardPorts < Base
|
5
|
+
def execute!
|
6
|
+
clear
|
7
|
+
forward_ports
|
8
|
+
end
|
9
|
+
|
10
|
+
def clear
|
11
|
+
logger.info "Deleting any previously set forwarded ports..."
|
12
|
+
@runner.vm.forwarded_ports.collect { |p| p.destroy(true) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def forward_ports
|
16
|
+
logger.info "Forwarding ports..."
|
17
|
+
|
18
|
+
Vagrant.config.vm.forwarded_ports.each do |name, options|
|
19
|
+
logger.info "Forwarding \"#{name}\": #{options[:guestport]} => #{options[:hostport]}"
|
20
|
+
port = VirtualBox::ForwardedPort.new
|
21
|
+
port.name = name
|
22
|
+
port.hostport = options[:hostport]
|
23
|
+
port.guestport = options[:guestport]
|
24
|
+
@runner.vm.forwarded_ports << port
|
25
|
+
end
|
26
|
+
|
27
|
+
@runner.vm.save(true)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Actions
|
3
|
+
module VM
|
4
|
+
class Halt < Base
|
5
|
+
def execute!
|
6
|
+
raise ActionException.new("VM is not running! Nothing to shut down!") unless @runner.vm.running?
|
7
|
+
|
8
|
+
logger.info "Forcing shutdown of VM..."
|
9
|
+
@runner.vm.stop(true)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Actions
|
3
|
+
module VM
|
4
|
+
class Import < Base
|
5
|
+
def execute!
|
6
|
+
@runner.invoke_around_callback(:import) do
|
7
|
+
Busy.busy do
|
8
|
+
logger.info "Importing base VM (#{Vagrant::Env.box.ovf_file})..."
|
9
|
+
# Use the first argument passed to the action
|
10
|
+
@runner.vm = VirtualBox::VM.import(Vagrant::Env.box.ovf_file)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Actions
|
3
|
+
module VM
|
4
|
+
class MoveHardDrive < Base
|
5
|
+
def execute!
|
6
|
+
unless @runner.powered_off?
|
7
|
+
error_and_exit(<<-error)
|
8
|
+
The virtual machine must be powered off to move its disk.
|
9
|
+
error
|
10
|
+
return
|
11
|
+
end
|
12
|
+
|
13
|
+
destroy_drive_after { clone_and_attach }
|
14
|
+
end
|
15
|
+
|
16
|
+
def hard_drive
|
17
|
+
@hard_drive ||= find_hard_drive
|
18
|
+
end
|
19
|
+
|
20
|
+
# TODO won't work if the first disk is not the boot disk or even if there are multiple disks
|
21
|
+
def find_hard_drive
|
22
|
+
@runner.vm.storage_controllers.each do |sc|
|
23
|
+
sc.devices.each do |d|
|
24
|
+
return d if d.image.is_a?(VirtualBox::HardDrive)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def clone_and_attach
|
30
|
+
logger.info "Cloning current VM Disk to new location (#{new_image_path})..."
|
31
|
+
hard_drive.image = hard_drive.image.clone(new_image_path, Vagrant.config.vm.disk_image_format, true)
|
32
|
+
|
33
|
+
logger.info "Attaching new disk to VM ..."
|
34
|
+
@runner.vm.save
|
35
|
+
end
|
36
|
+
|
37
|
+
def destroy_drive_after
|
38
|
+
old_image = hard_drive.image
|
39
|
+
|
40
|
+
yield
|
41
|
+
|
42
|
+
logger.info "Destroying old VM Disk (#{old_image.filename})..."
|
43
|
+
old_image.destroy(true)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the path to the new location for the hard drive
|
47
|
+
def new_image_path
|
48
|
+
File.join(Vagrant.config.vm.hd_location, hard_drive.image.filename)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Actions
|
3
|
+
module VM
|
4
|
+
class Package < Base
|
5
|
+
attr_accessor :out_path
|
6
|
+
attr_accessor :include_files
|
7
|
+
attr_reader :export_action
|
8
|
+
|
9
|
+
def initialize(vm, out_path = nil, include_files = nil, *args)
|
10
|
+
super
|
11
|
+
@out_path = out_path || "package"
|
12
|
+
@include_files = include_files || []
|
13
|
+
@temp_path = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def prepare
|
17
|
+
# Verify the existance of all the additional files, if any
|
18
|
+
@include_files.each do |file|
|
19
|
+
raise ActionException.new("#{file} does not exist") unless File.exists?(file)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Get the export action and store a reference to it
|
23
|
+
@export_action = @runner.find_action(Export)
|
24
|
+
raise ActionException.new("Package must be used in conjunction with export.") unless @export_action
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute!
|
28
|
+
compress
|
29
|
+
end
|
30
|
+
|
31
|
+
def tar_path
|
32
|
+
File.join(FileUtils.pwd, "#{out_path}#{Vagrant.config.package.extension}")
|
33
|
+
end
|
34
|
+
|
35
|
+
def temp_path
|
36
|
+
export_action.temp_dir
|
37
|
+
end
|
38
|
+
|
39
|
+
def compress
|
40
|
+
logger.info "Packaging VM into #{tar_path} ..."
|
41
|
+
Tar.open(tar_path, File::CREAT | File::WRONLY, 0644, Tar::GNU) do |tar|
|
42
|
+
begin
|
43
|
+
current_dir = FileUtils.pwd
|
44
|
+
@include_files.each do |f|
|
45
|
+
logger.info "Packaging additional file: #{f}"
|
46
|
+
tar.append_file(f)
|
47
|
+
end
|
48
|
+
|
49
|
+
FileUtils.cd(temp_path)
|
50
|
+
|
51
|
+
# Append tree will append the entire directory tree unless a relative folder reference is used
|
52
|
+
tar.append_tree(".")
|
53
|
+
ensure
|
54
|
+
FileUtils.cd(current_dir)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Actions
|
3
|
+
module VM
|
4
|
+
class Provision < Base
|
5
|
+
def execute!
|
6
|
+
chown_provisioning_folder
|
7
|
+
setup_json
|
8
|
+
setup_solo_config
|
9
|
+
run_chef_solo
|
10
|
+
end
|
11
|
+
|
12
|
+
def chown_provisioning_folder
|
13
|
+
logger.info "Setting permissions on provisioning folder..."
|
14
|
+
SSH.execute do |ssh|
|
15
|
+
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def setup_json
|
20
|
+
logger.info "Generating JSON and uploading..."
|
21
|
+
|
22
|
+
# Set up initial configuration
|
23
|
+
data = {
|
24
|
+
:config => Vagrant.config,
|
25
|
+
:directory => Vagrant.config.vm.project_directory,
|
26
|
+
}
|
27
|
+
|
28
|
+
# And wrap it under the "vagrant" namespace
|
29
|
+
data = { :vagrant => data }
|
30
|
+
|
31
|
+
# Merge with the "extra data" which isn't put under the
|
32
|
+
# vagrant namespace by default
|
33
|
+
data.merge!(Vagrant.config.chef.json)
|
34
|
+
|
35
|
+
json = data.to_json
|
36
|
+
|
37
|
+
SSH.upload!(StringIO.new(json), File.join(Vagrant.config.chef.provisioning_path, "dna.json"))
|
38
|
+
end
|
39
|
+
|
40
|
+
def setup_solo_config
|
41
|
+
solo_file = <<-solo
|
42
|
+
file_cache_path "#{Vagrant.config.chef.provisioning_path}"
|
43
|
+
cookbook_path "#{cookbooks_path}"
|
44
|
+
solo
|
45
|
+
|
46
|
+
logger.info "Uploading chef-solo configuration script..."
|
47
|
+
SSH.upload!(StringIO.new(solo_file), File.join(Vagrant.config.chef.provisioning_path, "solo.rb"))
|
48
|
+
end
|
49
|
+
|
50
|
+
def run_chef_solo
|
51
|
+
logger.info "Running chef recipes..."
|
52
|
+
SSH.execute do |ssh|
|
53
|
+
ssh.exec!("cd #{Vagrant.config.chef.provisioning_path} && sudo chef-solo -c solo.rb -j dna.json") do |channel, data, stream|
|
54
|
+
# TODO: Very verbose. It would be easier to save the data and only show it during
|
55
|
+
# an error, or when verbosity level is set high
|
56
|
+
logger.info("#{stream}: #{data}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def cookbooks_path
|
62
|
+
File.join(Vagrant.config.chef.provisioning_path, "cookbooks")
|
63
|
+
end
|
64
|
+
|
65
|
+
def collect_shared_folders
|
66
|
+
["vagrant-provisioning", File.expand_path(Vagrant.config.chef.cookbooks_path, Env.root_path), cookbooks_path]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Actions
|
3
|
+
module VM
|
4
|
+
class Reload < Base
|
5
|
+
def prepare
|
6
|
+
steps = [ForwardPorts, SharedFolders, Start]
|
7
|
+
steps.unshift(Halt) if @runner.vm.running?
|
8
|
+
steps << Provision if Vagrant.config.chef.enabled
|
9
|
+
|
10
|
+
steps.each do |action_klass|
|
11
|
+
@runner.add_action(action_klass)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Actions
|
3
|
+
module VM
|
4
|
+
class Resume < Base
|
5
|
+
def execute!
|
6
|
+
if !@runner.vm.saved?
|
7
|
+
raise ActionException.new("The vagrant virtual environment you are trying to resume is not in a suspended state.")
|
8
|
+
end
|
9
|
+
|
10
|
+
logger.info "Resuming suspended VM..."
|
11
|
+
@runner.start
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Actions
|
3
|
+
module VM
|
4
|
+
class SharedFolders < Base
|
5
|
+
def shared_folders
|
6
|
+
shared_folders = @runner.invoke_callback(:collect_shared_folders)
|
7
|
+
|
8
|
+
# Basic filtering of shared folders. Basically only verifies that
|
9
|
+
# the result is an array of 3 elements. In the future this should
|
10
|
+
# also verify that the host path exists, the name is valid,
|
11
|
+
# and that the guest path is valid.
|
12
|
+
shared_folders.collect do |folder|
|
13
|
+
if folder.is_a?(Array) && folder.length == 3
|
14
|
+
folder
|
15
|
+
else
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
end.compact
|
19
|
+
end
|
20
|
+
|
21
|
+
def before_boot
|
22
|
+
logger.info "Creating shared folders metadata..."
|
23
|
+
|
24
|
+
shared_folders.each do |name, hostpath, guestpath|
|
25
|
+
folder = VirtualBox::SharedFolder.new
|
26
|
+
folder.name = name
|
27
|
+
folder.hostpath = hostpath
|
28
|
+
@runner.vm.shared_folders << folder
|
29
|
+
end
|
30
|
+
|
31
|
+
@runner.vm.save(true)
|
32
|
+
end
|
33
|
+
|
34
|
+
def after_boot
|
35
|
+
logger.info "Mounting shared folders..."
|
36
|
+
|
37
|
+
Vagrant::SSH.execute do |ssh|
|
38
|
+
shared_folders.each do |name, hostpath, guestpath|
|
39
|
+
logger.info "-- #{name}: #{guestpath}"
|
40
|
+
ssh.exec!("sudo mkdir -p #{guestpath}")
|
41
|
+
mount_folder(ssh, name, guestpath)
|
42
|
+
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{guestpath}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def mount_folder(ssh, name, guestpath, sleeptime=5)
|
48
|
+
# Note: This method seems pretty OS-specific and could also use
|
49
|
+
# some configuration options. For now its duct tape and "works"
|
50
|
+
# but should be looked at in the future.
|
51
|
+
attempts = 0
|
52
|
+
|
53
|
+
while true
|
54
|
+
result = ssh.exec!("sudo mount -t vboxsf #{name} #{guestpath}") do |ch, type, data|
|
55
|
+
# net/ssh returns the value in ch[:result] (based on looking at source)
|
56
|
+
ch[:result] = !!(type == :stderr && data =~ /No such device/i)
|
57
|
+
end
|
58
|
+
|
59
|
+
break unless result
|
60
|
+
|
61
|
+
attempts += 1
|
62
|
+
raise ActionException.new("Failed to mount shared folders. vboxsf was not available.") if attempts >= 10
|
63
|
+
sleep sleeptime
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Actions
|
3
|
+
module VM
|
4
|
+
class Start < Base
|
5
|
+
def execute!
|
6
|
+
@runner.invoke_around_callback(:boot) do
|
7
|
+
# Startup the VM
|
8
|
+
boot
|
9
|
+
|
10
|
+
# Wait for it to complete booting, or error if we could
|
11
|
+
# never detect it booted up successfully
|
12
|
+
if !wait_for_boot
|
13
|
+
error_and_exit(<<-error)
|
14
|
+
Failed to connect to VM! Failed to boot?
|
15
|
+
error
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def collect_shared_folders
|
21
|
+
# The root shared folder for the project
|
22
|
+
["vagrant-root", Env.root_path, Vagrant.config.vm.project_directory]
|
23
|
+
end
|
24
|
+
|
25
|
+
def boot
|
26
|
+
logger.info "Booting VM..."
|
27
|
+
@runner.vm.start(:headless, true)
|
28
|
+
end
|
29
|
+
|
30
|
+
def wait_for_boot(sleeptime=5)
|
31
|
+
logger.info "Waiting for VM to boot..."
|
32
|
+
|
33
|
+
Vagrant.config[:ssh][:max_tries].to_i.times do |i|
|
34
|
+
logger.info "Trying to connect (attempt ##{i+1} of #{Vagrant.config[:ssh][:max_tries]})..."
|
35
|
+
|
36
|
+
if Vagrant::SSH.up?
|
37
|
+
logger.info "VM booted and ready for use!"
|
38
|
+
return true
|
39
|
+
end
|
40
|
+
|
41
|
+
sleep sleeptime
|
42
|
+
end
|
43
|
+
|
44
|
+
logger.info "Failed to connect to VM! Failed to boot?"
|
45
|
+
false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|