vagrantup 0.1.0

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.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/Gemfile +17 -0
  4. data/README.md +45 -0
  5. data/Rakefile +41 -0
  6. data/VERSION +1 -0
  7. data/bin/.gitignore +0 -0
  8. data/bin/vagrant +15 -0
  9. data/bin/vagrant-box +35 -0
  10. data/bin/vagrant-down +28 -0
  11. data/bin/vagrant-halt +29 -0
  12. data/bin/vagrant-init +28 -0
  13. data/bin/vagrant-package +30 -0
  14. data/bin/vagrant-reload +30 -0
  15. data/bin/vagrant-resume +28 -0
  16. data/bin/vagrant-ssh +28 -0
  17. data/bin/vagrant-suspend +28 -0
  18. data/bin/vagrant-up +30 -0
  19. data/config/default.rb +29 -0
  20. data/lib/vagrant.rb +14 -0
  21. data/lib/vagrant/actions/base.rb +93 -0
  22. data/lib/vagrant/actions/box/add.rb +22 -0
  23. data/lib/vagrant/actions/box/destroy.rb +14 -0
  24. data/lib/vagrant/actions/box/download.rb +63 -0
  25. data/lib/vagrant/actions/box/unpackage.rb +49 -0
  26. data/lib/vagrant/actions/runner.rb +128 -0
  27. data/lib/vagrant/actions/vm/destroy.rb +14 -0
  28. data/lib/vagrant/actions/vm/down.rb +12 -0
  29. data/lib/vagrant/actions/vm/export.rb +41 -0
  30. data/lib/vagrant/actions/vm/forward_ports.rb +32 -0
  31. data/lib/vagrant/actions/vm/halt.rb +14 -0
  32. data/lib/vagrant/actions/vm/import.rb +17 -0
  33. data/lib/vagrant/actions/vm/move_hard_drive.rb +53 -0
  34. data/lib/vagrant/actions/vm/package.rb +61 -0
  35. data/lib/vagrant/actions/vm/provision.rb +71 -0
  36. data/lib/vagrant/actions/vm/reload.rb +17 -0
  37. data/lib/vagrant/actions/vm/resume.rb +16 -0
  38. data/lib/vagrant/actions/vm/shared_folders.rb +69 -0
  39. data/lib/vagrant/actions/vm/start.rb +50 -0
  40. data/lib/vagrant/actions/vm/suspend.rb +16 -0
  41. data/lib/vagrant/actions/vm/up.rb +35 -0
  42. data/lib/vagrant/box.rb +129 -0
  43. data/lib/vagrant/busy.rb +73 -0
  44. data/lib/vagrant/commands.rb +174 -0
  45. data/lib/vagrant/config.rb +156 -0
  46. data/lib/vagrant/downloaders/base.rb +13 -0
  47. data/lib/vagrant/downloaders/file.rb +21 -0
  48. data/lib/vagrant/downloaders/http.rb +47 -0
  49. data/lib/vagrant/env.rb +140 -0
  50. data/lib/vagrant/ssh.rb +43 -0
  51. data/lib/vagrant/util.rb +45 -0
  52. data/lib/vagrant/vm.rb +57 -0
  53. data/script/vagrant-ssh-expect.sh +22 -0
  54. data/templates/Vagrantfile +8 -0
  55. data/test/test_helper.rb +91 -0
  56. data/test/vagrant/actions/base_test.rb +32 -0
  57. data/test/vagrant/actions/box/add_test.rb +37 -0
  58. data/test/vagrant/actions/box/destroy_test.rb +18 -0
  59. data/test/vagrant/actions/box/download_test.rb +118 -0
  60. data/test/vagrant/actions/box/unpackage_test.rb +101 -0
  61. data/test/vagrant/actions/runner_test.rb +236 -0
  62. data/test/vagrant/actions/vm/destroy_test.rb +24 -0
  63. data/test/vagrant/actions/vm/down_test.rb +32 -0
  64. data/test/vagrant/actions/vm/export_test.rb +88 -0
  65. data/test/vagrant/actions/vm/forward_ports_test.rb +50 -0
  66. data/test/vagrant/actions/vm/halt_test.rb +27 -0
  67. data/test/vagrant/actions/vm/import_test.rb +36 -0
  68. data/test/vagrant/actions/vm/move_hard_drive_test.rb +108 -0
  69. data/test/vagrant/actions/vm/package_test.rb +155 -0
  70. data/test/vagrant/actions/vm/provision_test.rb +103 -0
  71. data/test/vagrant/actions/vm/reload_test.rb +44 -0
  72. data/test/vagrant/actions/vm/resume_test.rb +27 -0
  73. data/test/vagrant/actions/vm/shared_folders_test.rb +117 -0
  74. data/test/vagrant/actions/vm/start_test.rb +55 -0
  75. data/test/vagrant/actions/vm/suspend_test.rb +27 -0
  76. data/test/vagrant/actions/vm/up_test.rb +76 -0
  77. data/test/vagrant/box_test.rb +92 -0
  78. data/test/vagrant/busy_test.rb +81 -0
  79. data/test/vagrant/commands_test.rb +252 -0
  80. data/test/vagrant/config_test.rb +123 -0
  81. data/test/vagrant/downloaders/base_test.rb +20 -0
  82. data/test/vagrant/downloaders/file_test.rb +32 -0
  83. data/test/vagrant/downloaders/http_test.rb +40 -0
  84. data/test/vagrant/env_test.rb +293 -0
  85. data/test/vagrant/ssh_test.rb +95 -0
  86. data/test/vagrant/util_test.rb +64 -0
  87. data/test/vagrant/vm_test.rb +96 -0
  88. metadata +263 -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