vagrant 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/.gitignore +11 -0
  2. data/Gemfile +17 -0
  3. data/README.md +45 -0
  4. data/Rakefile +41 -0
  5. data/VERSION +1 -0
  6. data/bin/.gitignore +0 -0
  7. data/bin/vagrant +15 -0
  8. data/bin/vagrant-box +35 -0
  9. data/bin/vagrant-down +28 -0
  10. data/bin/vagrant-halt +29 -0
  11. data/bin/vagrant-init +28 -0
  12. data/bin/vagrant-package +30 -0
  13. data/bin/vagrant-reload +30 -0
  14. data/bin/vagrant-resume +28 -0
  15. data/bin/vagrant-ssh +28 -0
  16. data/bin/vagrant-suspend +28 -0
  17. data/bin/vagrant-up +30 -0
  18. data/config/default.rb +29 -0
  19. data/lib/vagrant.rb +14 -0
  20. data/lib/vagrant/actions/base.rb +93 -0
  21. data/lib/vagrant/actions/box/add.rb +22 -0
  22. data/lib/vagrant/actions/box/destroy.rb +14 -0
  23. data/lib/vagrant/actions/box/download.rb +63 -0
  24. data/lib/vagrant/actions/box/unpackage.rb +49 -0
  25. data/lib/vagrant/actions/runner.rb +128 -0
  26. data/lib/vagrant/actions/vm/destroy.rb +14 -0
  27. data/lib/vagrant/actions/vm/down.rb +12 -0
  28. data/lib/vagrant/actions/vm/export.rb +41 -0
  29. data/lib/vagrant/actions/vm/forward_ports.rb +32 -0
  30. data/lib/vagrant/actions/vm/halt.rb +14 -0
  31. data/lib/vagrant/actions/vm/import.rb +17 -0
  32. data/lib/vagrant/actions/vm/move_hard_drive.rb +53 -0
  33. data/lib/vagrant/actions/vm/package.rb +61 -0
  34. data/lib/vagrant/actions/vm/provision.rb +71 -0
  35. data/lib/vagrant/actions/vm/reload.rb +17 -0
  36. data/lib/vagrant/actions/vm/resume.rb +16 -0
  37. data/lib/vagrant/actions/vm/shared_folders.rb +69 -0
  38. data/lib/vagrant/actions/vm/start.rb +50 -0
  39. data/lib/vagrant/actions/vm/suspend.rb +16 -0
  40. data/lib/vagrant/actions/vm/up.rb +35 -0
  41. data/lib/vagrant/box.rb +129 -0
  42. data/lib/vagrant/busy.rb +73 -0
  43. data/lib/vagrant/commands.rb +174 -0
  44. data/lib/vagrant/config.rb +156 -0
  45. data/lib/vagrant/downloaders/base.rb +13 -0
  46. data/lib/vagrant/downloaders/file.rb +21 -0
  47. data/lib/vagrant/downloaders/http.rb +47 -0
  48. data/lib/vagrant/env.rb +140 -0
  49. data/lib/vagrant/ssh.rb +43 -0
  50. data/lib/vagrant/util.rb +45 -0
  51. data/lib/vagrant/vm.rb +57 -0
  52. data/script/vagrant-ssh-expect.sh +22 -0
  53. data/templates/Vagrantfile +8 -0
  54. data/test/test_helper.rb +91 -0
  55. data/test/vagrant/actions/base_test.rb +32 -0
  56. data/test/vagrant/actions/box/add_test.rb +37 -0
  57. data/test/vagrant/actions/box/destroy_test.rb +18 -0
  58. data/test/vagrant/actions/box/download_test.rb +118 -0
  59. data/test/vagrant/actions/box/unpackage_test.rb +101 -0
  60. data/test/vagrant/actions/runner_test.rb +236 -0
  61. data/test/vagrant/actions/vm/destroy_test.rb +24 -0
  62. data/test/vagrant/actions/vm/down_test.rb +32 -0
  63. data/test/vagrant/actions/vm/export_test.rb +88 -0
  64. data/test/vagrant/actions/vm/forward_ports_test.rb +50 -0
  65. data/test/vagrant/actions/vm/halt_test.rb +27 -0
  66. data/test/vagrant/actions/vm/import_test.rb +36 -0
  67. data/test/vagrant/actions/vm/move_hard_drive_test.rb +108 -0
  68. data/test/vagrant/actions/vm/package_test.rb +155 -0
  69. data/test/vagrant/actions/vm/provision_test.rb +103 -0
  70. data/test/vagrant/actions/vm/reload_test.rb +44 -0
  71. data/test/vagrant/actions/vm/resume_test.rb +27 -0
  72. data/test/vagrant/actions/vm/shared_folders_test.rb +117 -0
  73. data/test/vagrant/actions/vm/start_test.rb +55 -0
  74. data/test/vagrant/actions/vm/suspend_test.rb +27 -0
  75. data/test/vagrant/actions/vm/up_test.rb +76 -0
  76. data/test/vagrant/box_test.rb +92 -0
  77. data/test/vagrant/busy_test.rb +81 -0
  78. data/test/vagrant/commands_test.rb +252 -0
  79. data/test/vagrant/config_test.rb +123 -0
  80. data/test/vagrant/downloaders/base_test.rb +20 -0
  81. data/test/vagrant/downloaders/file_test.rb +32 -0
  82. data/test/vagrant/downloaders/http_test.rb +40 -0
  83. data/test/vagrant/env_test.rb +293 -0
  84. data/test/vagrant/ssh_test.rb +95 -0
  85. data/test/vagrant/util_test.rb +64 -0
  86. data/test/vagrant/vm_test.rb +96 -0
  87. metadata +275 -0
@@ -0,0 +1,13 @@
1
+ module Vagrant
2
+ module Downloaders
3
+ # Represents a base class for a downloader. A downloader handles
4
+ # downloading a box file to a temporary file.
5
+ class Base
6
+ include Vagrant::Util
7
+
8
+ # Downloads the source file to the destination file. It is up to
9
+ # implementors of this class to handle the logic.
10
+ def download!(source_url, destination_file); end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module Vagrant
2
+ module Downloaders
3
+ # "Downloads" a file to a temporary file. Basically, this downloader
4
+ # simply does a file copy.
5
+ class File < Base
6
+ BUFFERSIZE = 1048576 # 1 MB
7
+
8
+ 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
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ module Vagrant
2
+ module Downloaders
3
+ # Downloads a file from an HTTP URL to a temporary file. This
4
+ # downloader reports its progress to stdout while downloading.
5
+ class HTTP < Base
6
+ # ANSI escape code to clear lines from cursor to end of line
7
+ CL_RESET = "\r\e[0K"
8
+
9
+ def download!(source_url, destination_file)
10
+ Net::HTTP.get_response(URI.parse(source_url)) do |response|
11
+ total = response.content_length
12
+ progress = 0
13
+ segment_count = 0
14
+
15
+ response.read_body do |segment|
16
+ # Report the progress out
17
+ progress += segment.length
18
+ segment_count += 1
19
+
20
+ # Progress reporting is limited to every 25 segments just so
21
+ # we're not constantly updating
22
+ if segment_count % 25 == 0
23
+ report_progress(progress, total)
24
+ segment_count = 0
25
+ end
26
+
27
+ # Store the segment
28
+ destination_file.write(segment)
29
+ end
30
+ end
31
+
32
+ complete_progress
33
+ end
34
+
35
+ def report_progress(progress, total)
36
+ percent = (progress.to_f / total.to_f) * 100
37
+ print "#{CL_RESET}Download Progress: #{percent.to_i}% (#{progress} / #{total})"
38
+ $stdout.flush
39
+ end
40
+
41
+ def complete_progress
42
+ # Just clear the line back out
43
+ print "#{CL_RESET}"
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,140 @@
1
+ module Vagrant
2
+ class Env
3
+ ROOTFILE_NAME = "Vagrantfile"
4
+ HOME_SUBDIRS = ["tmp", "boxes"]
5
+
6
+ # Initialize class variables used
7
+ @@persisted_vm = nil
8
+ @@root_path = nil
9
+ @@box = nil
10
+
11
+ extend Vagrant::Util
12
+
13
+ class << self
14
+ def box; @@box; end
15
+ def persisted_vm; @@persisted_vm; end
16
+ def root_path; @@root_path; end
17
+ def dotfile_path;File.join(root_path, Vagrant.config.vagrant.dotfile_name); end
18
+ def home_path; File.expand_path(Vagrant.config.vagrant.home); end
19
+ def tmp_path; File.join(home_path, "tmp"); end
20
+ def boxes_path; File.join(home_path, "boxes"); end
21
+
22
+ def load!(opts={})
23
+ load_root_path!(Pathname.new(Dir.pwd), opts)
24
+ load_config!
25
+ load_home_directory!
26
+ load_box!
27
+ load_vm!
28
+ end
29
+
30
+ def load_config!
31
+ # Prepare load paths for config files
32
+ load_paths = [File.join(PROJECT_ROOT, "config", "default.rb")]
33
+ load_paths << File.join(box.directory, ROOTFILE_NAME) if box
34
+ load_paths << File.join(root_path, ROOTFILE_NAME) if root_path
35
+
36
+ # Then clear out the old data
37
+ Config.reset!
38
+
39
+ load_paths.each do |path|
40
+ logger.info "Loading config from #{path}..."
41
+ load path if File.exist?(path)
42
+ end
43
+
44
+ # Execute the configurations
45
+ Config.execute!
46
+ end
47
+
48
+ def load_home_directory!
49
+ home_dir = File.expand_path(Vagrant.config.vagrant.home)
50
+
51
+ dirs = HOME_SUBDIRS.collect { |path| File.join(home_dir, path) }
52
+ dirs.unshift(home_dir)
53
+
54
+ dirs.each do |dir|
55
+ next if File.directory?(dir)
56
+
57
+ logger.info "Creating home directory since it doesn't exist: #{dir}"
58
+ FileUtils.mkdir_p(dir)
59
+ end
60
+ end
61
+
62
+ def load_box!
63
+ @@box = Box.find(Vagrant.config.vm.box) if Vagrant.config.vm.box
64
+
65
+ if @@box
66
+ logger.info("Reloading configuration to account for loaded box...")
67
+ load_config!
68
+ end
69
+ end
70
+
71
+ def load_vm!
72
+ return unless root_path
73
+
74
+ File.open(dotfile_path) do |f|
75
+ @@persisted_vm = Vagrant::VM.find(f.read)
76
+ end
77
+ rescue Errno::ENOENT
78
+ @@persisted_vm = nil
79
+ end
80
+
81
+ def persist_vm(vm)
82
+ File.open(dotfile_path, 'w+') do |f|
83
+ f.write(vm.uuid)
84
+ end
85
+ end
86
+
87
+ def load_root_path!(path=Pathname.new(Dir.pwd), opts={})
88
+ if path.to_s == '/'
89
+ return false if opts[:suppress_errors]
90
+ error_and_exit(<<-msg)
91
+ A `#{ROOTFILE_NAME}` was not found! This file is required for vagrant to run
92
+ since it describes the expected environment that vagrant is supposed
93
+ to manage. Please create a #{ROOTFILE_NAME} and place it in your project
94
+ root.
95
+ msg
96
+ return
97
+ end
98
+
99
+ file = "#{path}/#{ROOTFILE_NAME}"
100
+ if File.exist?(file)
101
+ @@root_path = path.to_s
102
+ return true
103
+ end
104
+
105
+ load_root_path!(path.parent, opts)
106
+ end
107
+
108
+ def require_box
109
+ if !box
110
+ if !Vagrant.config.vm.box
111
+ error_and_exit(<<-msg)
112
+ No base box was specified! A base box is required as a staring point
113
+ for every vagrant virtual machine. Please specify one in your Vagrantfile
114
+ using `config.vm.box`
115
+ msg
116
+ else
117
+ error_and_exit(<<-msg)
118
+ Specified box `#{Vagrant.config.vm.box}` does not exist!
119
+
120
+ The box must be added through the `vagrant box add` command. Please view
121
+ the documentation associated with the command for more information.
122
+ msg
123
+ end
124
+ end
125
+ end
126
+
127
+ def require_persisted_vm
128
+ if !persisted_vm
129
+ error_and_exit(<<-error)
130
+ The task you're trying to run requires that the vagrant environment
131
+ already be created, but unfortunately this vagrant still appears to
132
+ have no box! You can setup the environment by setting up your
133
+ #{ROOTFILE_NAME} and running `vagrant up`
134
+ error
135
+ return
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,43 @@
1
+ module Vagrant
2
+ class SSH
3
+ SCRIPT = File.join(File.dirname(__FILE__), '..', '..', 'script', 'vagrant-ssh-expect.sh')
4
+
5
+ class << self
6
+ def connect(opts={})
7
+ options = {}
8
+ [:host, :password, :username].each do |param|
9
+ options[param] = opts[param] || Vagrant.config.ssh.send(param)
10
+ end
11
+
12
+ Kernel.exec "#{SCRIPT} #{options[:username]} #{options[:password]} #{options[:host]} #{port(opts)}".strip
13
+ end
14
+
15
+ def execute
16
+ Net::SSH.start(Vagrant.config.ssh.host, Vagrant.config[:ssh][:username], :port => port, :password => Vagrant.config[:ssh][:password]) do |ssh|
17
+ yield ssh
18
+ end
19
+ end
20
+
21
+ def upload!(from, to)
22
+ execute do |ssh|
23
+ scp = Net::SCP.new(ssh)
24
+ scp.upload!(from, to)
25
+ end
26
+ end
27
+
28
+ def up?
29
+ Net::SSH.start(Vagrant.config.ssh.host, Vagrant.config.ssh.username, :port => port, :password => Vagrant.config.ssh.password, :timeout => 5) do |ssh|
30
+ return true
31
+ end
32
+
33
+ false
34
+ rescue Errno::ECONNREFUSED, Net::SSH::Disconnect
35
+ false
36
+ end
37
+
38
+ def port(opts={})
39
+ opts[:port] || Vagrant.config.vm.forwarded_ports[Vagrant.config.ssh.forwarded_port_key][:hostport]
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,45 @@
1
+ module Vagrant
2
+ module Util
3
+ def self.included(base)
4
+ base.extend Vagrant::Util
5
+ end
6
+
7
+ def error_and_exit(error)
8
+ abort <<-error
9
+ =====================================================================
10
+ Vagrant experienced an error!
11
+
12
+ #{error.chomp}
13
+ =====================================================================
14
+ error
15
+ end
16
+
17
+ def logger
18
+ Logger.singleton_logger
19
+ end
20
+ end
21
+
22
+ class Logger < ::Logger
23
+ @@singleton_logger = nil
24
+
25
+ class << self
26
+ def singleton_logger
27
+ # TODO: Buffer messages until config is loaded, then output them?
28
+ if Vagrant.config.loaded?
29
+ @@singleton_logger ||= Vagrant::Logger.new(Vagrant.config.vagrant.log_output)
30
+ else
31
+ Vagrant::Logger.new(nil)
32
+ end
33
+ end
34
+
35
+ def reset_logger!
36
+ @@singleton_logger = nil
37
+ end
38
+ end
39
+
40
+ def format_message(level, time, progname, msg)
41
+ "[#{level} #{time.strftime('%m-%d-%Y %X')}] Vagrant: #{msg}\n"
42
+ end
43
+ end
44
+ end
45
+
@@ -0,0 +1,57 @@
1
+ module Vagrant
2
+ class VM < Actions::Runner
3
+ include Vagrant::Util
4
+
5
+ attr_accessor :vm
6
+ attr_accessor :from
7
+
8
+ class << self
9
+ # Finds a virtual machine by a given UUID and either returns
10
+ # a Vagrant::VM object or returns nil.
11
+ def find(uuid)
12
+ vm = VirtualBox::VM.find(uuid)
13
+ return nil if vm.nil?
14
+ new(vm)
15
+ end
16
+ end
17
+
18
+ def initialize(vm=nil)
19
+ @vm = vm
20
+ end
21
+
22
+ def package(out_path, include_files=[])
23
+ add_action(Actions::VM::Export)
24
+ add_action(Actions::VM::Package, out_path, include_files)
25
+ execute!
26
+ end
27
+
28
+ def start
29
+ return if @vm.running?
30
+
31
+ actions = [Actions::VM::ForwardPorts, Actions::VM::SharedFolders, Actions::VM::Start]
32
+ actions.each do |action|
33
+ add_action(action)
34
+ end
35
+
36
+ execute!
37
+ end
38
+
39
+ def destroy
40
+ execute!(Actions::VM::Down)
41
+ end
42
+
43
+ def suspend
44
+ execute!(Actions::VM::Suspend)
45
+ end
46
+
47
+ def resume
48
+ execute!(Actions::VM::Resume)
49
+ end
50
+
51
+ def saved?
52
+ @vm.saved?
53
+ end
54
+
55
+ def powered_off?; @vm.powered_off? end
56
+ end
57
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/expect
2
+
3
+ set uname [lrange $argv 0 0]
4
+ set password [lrange $argv 1 1]
5
+ set host [lrange $argv 2 2]
6
+ set port [lrange $argv 3 3]
7
+
8
+ if { $port != "" } {
9
+ set port_option "-p $port"
10
+ } else {
11
+ set port_option ""
12
+ }
13
+
14
+ spawn ssh $port_option -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $uname@$host
15
+
16
+ expect "*password: " {
17
+ send "$password\r"
18
+ } timeout {
19
+ send_user "Error connecting"
20
+ }
21
+
22
+ interact
@@ -0,0 +1,8 @@
1
+ Vagrant::Config.run do |config|
2
+ # All Vagrant configuration is done here. For a detailed explanation
3
+ # and listing of configuration options, please check the documentation
4
+ # online.
5
+
6
+ # Every Vagrant virtual environment requires a box to build off of.
7
+ config.vm.box = "base"
8
+ end
@@ -0,0 +1,91 @@
1
+ begin
2
+ require File.expand_path('../.bundle/environment', __FILE__)
3
+ rescue LoadError
4
+ # Fallback on doing the resolve at runtime.
5
+ require "rubygems"
6
+ require "bundler"
7
+ Bundler.setup
8
+ end
9
+
10
+ # ruby-debug, not necessary, but useful if we have it
11
+ begin
12
+ require 'ruby-debug'
13
+ rescue LoadError; end
14
+
15
+
16
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'vagrant')
17
+ require 'contest'
18
+ require 'mocha'
19
+
20
+ class Test::Unit::TestCase
21
+ # Clears the previous config and sets up the new config
22
+ def mock_config
23
+ Vagrant::Config.instance_variable_set(:@config_runners, nil)
24
+ Vagrant::Config.instance_variable_set(:@config, nil)
25
+
26
+ Vagrant::Config.run do |config|
27
+ config.vagrant.dotfile_name = ".hobo"
28
+
29
+ config.ssh.username = "foo"
30
+ config.ssh.password = "bar"
31
+ config.ssh.host = "baz"
32
+ config.ssh.forwarded_port_key = "ssh"
33
+ config.ssh.max_tries = 10
34
+
35
+ config.vm.box = "foo"
36
+ config.vm.box_ovf = "box.ovf"
37
+ config.vm.base_mac = "42"
38
+ config.vm.project_directory = "/hobo"
39
+ config.vm.disk_image_format = 'VMDK'
40
+ config.vm.forward_port("ssh", 22, 2222)
41
+
42
+ config.package.name = 'vagrant'
43
+ config.package.extension = '.box'
44
+
45
+ config.chef.cookbooks_path = "cookbooks"
46
+ config.chef.provisioning_path = "/tmp/hobo-chef"
47
+ config.chef.json = {
48
+ :recipes => ["hobo_main"]
49
+ }
50
+
51
+ config.vagrant.home = '~/.home'
52
+ end
53
+
54
+ if block_given?
55
+ Vagrant::Config.run do |config|
56
+ yield config
57
+ end
58
+ end
59
+
60
+ if block_given?
61
+ Vagrant::Config.run do |config|
62
+ yield config
63
+ end
64
+ end
65
+
66
+ Vagrant::Config.execute!
67
+ end
68
+
69
+ # Sets up the mocks and instantiates an action for testing
70
+ def mock_action(action_klass, *args)
71
+ vm = mock("vboxvm")
72
+ mock_vm = mock("vm")
73
+ action = action_klass.new(mock_vm, *args)
74
+
75
+ mock_vm.stubs(:vm).returns(vm)
76
+ mock_vm.stubs(:vm=)
77
+ mock_vm.stubs(:invoke_callback)
78
+ mock_vm.stubs(:invoke_around_callback).yields
79
+ mock_vm.stubs(:actions).returns([action])
80
+
81
+ [mock_vm, vm, action]
82
+ end
83
+
84
+ # Sets up the mocks and stubs for a downloader
85
+ def mock_downloader(downloader_klass)
86
+ tempfile = mock("tempfile")
87
+ tempfile.stubs(:write)
88
+
89
+ [downloader_klass.new, tempfile]
90
+ end
91
+ end