bmabey-vagrant 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. data/.gitignore +12 -0
  2. data/Gemfile +17 -0
  3. data/LICENSE +21 -0
  4. data/README.md +53 -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 +34 -0
  10. data/bin/vagrant-down +27 -0
  11. data/bin/vagrant-halt +28 -0
  12. data/bin/vagrant-init +27 -0
  13. data/bin/vagrant-package +29 -0
  14. data/bin/vagrant-reload +29 -0
  15. data/bin/vagrant-resume +27 -0
  16. data/bin/vagrant-ssh +27 -0
  17. data/bin/vagrant-status +29 -0
  18. data/bin/vagrant-suspend +27 -0
  19. data/bin/vagrant-up +29 -0
  20. data/config/default.rb +26 -0
  21. data/keys/README.md +10 -0
  22. data/keys/vagrant +27 -0
  23. data/keys/vagrant.pub +1 -0
  24. data/lib/vagrant.rb +19 -0
  25. data/lib/vagrant/actions/base.rb +118 -0
  26. data/lib/vagrant/actions/box/add.rb +22 -0
  27. data/lib/vagrant/actions/box/destroy.rb +14 -0
  28. data/lib/vagrant/actions/box/download.rb +72 -0
  29. data/lib/vagrant/actions/box/unpackage.rb +43 -0
  30. data/lib/vagrant/actions/collection.rb +36 -0
  31. data/lib/vagrant/actions/runner.rb +132 -0
  32. data/lib/vagrant/actions/vm/boot.rb +47 -0
  33. data/lib/vagrant/actions/vm/customize.rb +17 -0
  34. data/lib/vagrant/actions/vm/destroy.rb +23 -0
  35. data/lib/vagrant/actions/vm/down.rb +12 -0
  36. data/lib/vagrant/actions/vm/export.rb +41 -0
  37. data/lib/vagrant/actions/vm/forward_ports.rb +46 -0
  38. data/lib/vagrant/actions/vm/halt.rb +14 -0
  39. data/lib/vagrant/actions/vm/import.rb +18 -0
  40. data/lib/vagrant/actions/vm/move_hard_drive.rb +51 -0
  41. data/lib/vagrant/actions/vm/package.rb +65 -0
  42. data/lib/vagrant/actions/vm/provision.rb +49 -0
  43. data/lib/vagrant/actions/vm/reload.rb +17 -0
  44. data/lib/vagrant/actions/vm/resume.rb +16 -0
  45. data/lib/vagrant/actions/vm/shared_folders.rb +81 -0
  46. data/lib/vagrant/actions/vm/start.rb +18 -0
  47. data/lib/vagrant/actions/vm/suspend.rb +16 -0
  48. data/lib/vagrant/actions/vm/up.rb +40 -0
  49. data/lib/vagrant/active_list.rb +73 -0
  50. data/lib/vagrant/box.rb +152 -0
  51. data/lib/vagrant/busy.rb +73 -0
  52. data/lib/vagrant/commands.rb +219 -0
  53. data/lib/vagrant/config.rb +183 -0
  54. data/lib/vagrant/downloaders/base.rb +16 -0
  55. data/lib/vagrant/downloaders/file.rb +17 -0
  56. data/lib/vagrant/downloaders/http.rb +47 -0
  57. data/lib/vagrant/environment.rb +263 -0
  58. data/lib/vagrant/provisioners/base.rb +29 -0
  59. data/lib/vagrant/provisioners/chef.rb +103 -0
  60. data/lib/vagrant/provisioners/chef_server.rb +84 -0
  61. data/lib/vagrant/provisioners/chef_solo.rb +97 -0
  62. data/lib/vagrant/ssh.rb +104 -0
  63. data/lib/vagrant/util.rb +51 -0
  64. data/lib/vagrant/util/errors.rb +36 -0
  65. data/lib/vagrant/util/stacked_proc_runner.rb +35 -0
  66. data/lib/vagrant/util/template_renderer.rb +83 -0
  67. data/lib/vagrant/vm.rb +61 -0
  68. data/templates/Vagrantfile.erb +8 -0
  69. data/templates/errors.yml +117 -0
  70. data/test/test_helper.rb +163 -0
  71. data/test/vagrant/actions/base_test.rb +32 -0
  72. data/test/vagrant/actions/box/add_test.rb +37 -0
  73. data/test/vagrant/actions/box/destroy_test.rb +18 -0
  74. data/test/vagrant/actions/box/download_test.rb +131 -0
  75. data/test/vagrant/actions/box/unpackage_test.rb +100 -0
  76. data/test/vagrant/actions/collection_test.rb +110 -0
  77. data/test/vagrant/actions/runner_test.rb +265 -0
  78. data/test/vagrant/actions/vm/boot_test.rb +55 -0
  79. data/test/vagrant/actions/vm/customize_test.rb +16 -0
  80. data/test/vagrant/actions/vm/destroy_test.rb +36 -0
  81. data/test/vagrant/actions/vm/down_test.rb +32 -0
  82. data/test/vagrant/actions/vm/export_test.rb +88 -0
  83. data/test/vagrant/actions/vm/forward_ports_test.rb +104 -0
  84. data/test/vagrant/actions/vm/halt_test.rb +27 -0
  85. data/test/vagrant/actions/vm/import_test.rb +43 -0
  86. data/test/vagrant/actions/vm/move_hard_drive_test.rb +108 -0
  87. data/test/vagrant/actions/vm/package_test.rb +181 -0
  88. data/test/vagrant/actions/vm/provision_test.rb +108 -0
  89. data/test/vagrant/actions/vm/reload_test.rb +47 -0
  90. data/test/vagrant/actions/vm/resume_test.rb +27 -0
  91. data/test/vagrant/actions/vm/shared_folders_test.rb +176 -0
  92. data/test/vagrant/actions/vm/start_test.rb +36 -0
  93. data/test/vagrant/actions/vm/suspend_test.rb +27 -0
  94. data/test/vagrant/actions/vm/up_test.rb +107 -0
  95. data/test/vagrant/active_list_test.rb +190 -0
  96. data/test/vagrant/box_test.rb +151 -0
  97. data/test/vagrant/busy_test.rb +83 -0
  98. data/test/vagrant/commands_test.rb +307 -0
  99. data/test/vagrant/config_test.rb +256 -0
  100. data/test/vagrant/downloaders/base_test.rb +27 -0
  101. data/test/vagrant/downloaders/file_test.rb +26 -0
  102. data/test/vagrant/downloaders/http_test.rb +40 -0
  103. data/test/vagrant/environment_test.rb +607 -0
  104. data/test/vagrant/provisioners/base_test.rb +33 -0
  105. data/test/vagrant/provisioners/chef_server_test.rb +187 -0
  106. data/test/vagrant/provisioners/chef_solo_test.rb +149 -0
  107. data/test/vagrant/provisioners/chef_test.rb +117 -0
  108. data/test/vagrant/ssh_test.rb +222 -0
  109. data/test/vagrant/util/errors_test.rb +57 -0
  110. data/test/vagrant/util/stacked_proc_runner_test.rb +43 -0
  111. data/test/vagrant/util/template_renderer_test.rb +138 -0
  112. data/test/vagrant/util_test.rb +64 -0
  113. data/test/vagrant/vm_test.rb +114 -0
  114. data/vagrant.gemspec +216 -0
  115. metadata +285 -0
@@ -0,0 +1,183 @@
1
+ module Vagrant
2
+ def self.config
3
+ Config.config
4
+ end
5
+
6
+ class Config
7
+ extend Util::StackedProcRunner
8
+
9
+ @@config = nil
10
+
11
+ class << self
12
+ def reset!(env=nil)
13
+ @@config = nil
14
+ proc_stack.clear
15
+
16
+ # Reset the configuration to the specified environment
17
+ config(env)
18
+ end
19
+
20
+ def configures(key, klass)
21
+ config.class.configures(key, klass)
22
+ end
23
+
24
+ def config(env=nil)
25
+ @@config ||= Config::Top.new(env)
26
+ end
27
+
28
+ def run(&block)
29
+ push_proc(&block)
30
+ end
31
+
32
+ def execute!
33
+ run_procs!(config)
34
+ config.loaded!
35
+ config
36
+ end
37
+ end
38
+ end
39
+
40
+ class Config
41
+ class Base
42
+ attr_accessor :env
43
+
44
+ def [](key)
45
+ send(key)
46
+ end
47
+
48
+ def to_json
49
+ instance_variables_hash.to_json
50
+ end
51
+
52
+ def instance_variables_hash
53
+ instance_variables.inject({}) do |acc, iv|
54
+ acc[iv.to_s[1..-1].to_sym] = instance_variable_get(iv)
55
+ acc
56
+ end
57
+ end
58
+ end
59
+
60
+ class SSHConfig < Base
61
+ attr_accessor :username
62
+ attr_accessor :password
63
+ attr_accessor :host
64
+ attr_accessor :forwarded_port_key
65
+ attr_accessor :max_tries
66
+ attr_accessor :timeout
67
+ attr_accessor :private_key_path
68
+
69
+ def private_key_path
70
+ File.expand_path(@private_key_path, env.root_path)
71
+ end
72
+ end
73
+
74
+ class VMConfig < Base
75
+ include Util::StackedProcRunner
76
+
77
+ attr_accessor :box
78
+ attr_accessor :box_ovf
79
+ attr_accessor :base_mac
80
+ attr_accessor :project_directory
81
+ attr_reader :forwarded_ports
82
+ attr_reader :shared_folders
83
+ attr_accessor :hd_location
84
+ attr_accessor :disk_image_format
85
+ attr_accessor :provisioner
86
+ attr_accessor :shared_folder_uid
87
+ attr_accessor :shared_folder_gid
88
+
89
+ def initialize
90
+ @forwarded_ports = {}
91
+ @shared_folders = {}
92
+ @provisioner = nil
93
+ end
94
+
95
+ def forward_port(name, guestport, hostport, protocol="TCP")
96
+ forwarded_ports[name] = {
97
+ :guestport => guestport,
98
+ :hostport => hostport,
99
+ :protocol => protocol
100
+ }
101
+ end
102
+
103
+ def share_folder(name, guestpath, hostpath)
104
+ @shared_folders[name] = {
105
+ :guestpath => guestpath,
106
+ :hostpath => hostpath
107
+ }
108
+ end
109
+
110
+ def hd_location=(val)
111
+ raise Exception.new("disk_storage must be set to a directory") unless File.directory?(val)
112
+ @hd_location=val
113
+ end
114
+
115
+ def shared_folder_uid
116
+ @shared_folder_uid || env.config.ssh.username
117
+ end
118
+
119
+ def shared_folder_gid
120
+ @shared_folder_gid || env.config.ssh.username
121
+ end
122
+
123
+ def customize(&block)
124
+ push_proc(&block)
125
+ end
126
+ end
127
+
128
+ class PackageConfig < Base
129
+ attr_accessor :name
130
+ attr_accessor :extension
131
+ end
132
+
133
+ class VagrantConfig < Base
134
+ attr_accessor :dotfile_name
135
+ attr_accessor :log_output
136
+ attr_accessor :home
137
+
138
+ def home
139
+ @home ? File.expand_path(@home) : nil
140
+ end
141
+ end
142
+
143
+ class Top < Base
144
+ @@configures = []
145
+
146
+ class <<self
147
+ def configures_list
148
+ @@configures ||= []
149
+ end
150
+
151
+ def configures(key, klass)
152
+ configures_list << [key, klass]
153
+ attr_reader key.to_sym
154
+ end
155
+ end
156
+
157
+ # Setup default configures
158
+ configures :package, PackageConfig
159
+ configures :ssh, SSHConfig
160
+ configures :vm, VMConfig
161
+ configures :vagrant, VagrantConfig
162
+
163
+ def initialize(env=nil)
164
+ self.class.configures_list.each do |key, klass|
165
+ config = klass.new
166
+ config.env = env
167
+ instance_variable_set("@#{key}".to_sym, config)
168
+ end
169
+
170
+ @loaded = false
171
+ @env = env
172
+ end
173
+
174
+ def loaded?
175
+ @loaded
176
+ end
177
+
178
+ def loaded!
179
+ @loaded = true
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,16 @@
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
+ # Called prior to execution so any error checks can be done
9
+ def prepare(source_url); end
10
+
11
+ # Downloads the source file to the destination file. It is up to
12
+ # implementors of this class to handle the logic.
13
+ def download!(source_url, destination_file); end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
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
+ def prepare(source_url)
7
+ if !::File.file?(source_url)
8
+ raise Actions::ActionException.new(:downloader_file_doesnt_exist, :source_url => source_url)
9
+ end
10
+ end
11
+
12
+ def download!(source_url, destination_file)
13
+ FileUtils.cp(source_url, destination_file.path)
14
+ end
15
+ end
16
+ end
17
+ 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,263 @@
1
+ module Vagrant
2
+ # Represents a single Vagrant environment. This class is responsible
3
+ # for loading all of the Vagrantfile's for the given environment and
4
+ # storing references to the various instances.
5
+ class Environment
6
+ ROOTFILE_NAME = "Vagrantfile"
7
+ HOME_SUBDIRS = ["tmp", "boxes"]
8
+
9
+ include Util
10
+
11
+ attr_accessor :cwd
12
+ attr_reader :root_path
13
+ attr_reader :config
14
+ attr_reader :box
15
+ attr_reader :vm
16
+ attr_reader :ssh
17
+ attr_reader :active_list
18
+ attr_reader :commands
19
+
20
+ #---------------------------------------------------------------
21
+ # Class Methods
22
+ #---------------------------------------------------------------
23
+ class <<self
24
+ # Loads and returns an environment given a specific working
25
+ # directory. If a working directory is not given, it will default
26
+ # to the pwd.
27
+ def load!(cwd=nil)
28
+ Environment.new(cwd).load!
29
+ end
30
+
31
+ # Verifies that VirtualBox is installed and that the version of
32
+ # VirtualBox installed is high enough. Also verifies that the
33
+ # configuration path is properly set.
34
+ def check_virtualbox!
35
+ version = VirtualBox::Command.version
36
+ if version.nil?
37
+ error_and_exit(:virtualbox_not_detected)
38
+ elsif version.to_f < 3.1
39
+ error_and_exit(:virtualbox_invalid_version, :version => version.to_s)
40
+ end
41
+
42
+ if !VirtualBox::Global.vboxconfig?
43
+ error_and_exit(:virtualbox_xml_not_detected)
44
+ end
45
+ end
46
+ end
47
+
48
+ def initialize(cwd=nil)
49
+ @cwd = cwd
50
+ end
51
+
52
+ #---------------------------------------------------------------
53
+ # Path Helpers
54
+ #---------------------------------------------------------------
55
+
56
+ # Specifies the "current working directory" for this environment.
57
+ # This is vital in determining the root path and therefore the
58
+ # dotfile, rootpath vagrantfile, etc. This defaults to the
59
+ # actual cwd (`Dir.pwd`).
60
+ def cwd
61
+ @cwd || Dir.pwd
62
+ end
63
+
64
+ # The path to the `dotfile`, which contains the persisted UUID of
65
+ # the VM if it exists.
66
+ def dotfile_path
67
+ File.join(root_path, config.vagrant.dotfile_name)
68
+ end
69
+
70
+ # The path to the home directory, which is usually in `~/.vagrant/~
71
+ def home_path
72
+ config ? config.vagrant.home : nil
73
+ end
74
+
75
+ # The path to the Vagrant tmp directory
76
+ def tmp_path
77
+ File.join(home_path, "tmp")
78
+ end
79
+
80
+ # The path to the Vagrant boxes directory
81
+ def boxes_path
82
+ File.join(home_path, "boxes")
83
+ end
84
+
85
+ #---------------------------------------------------------------
86
+ # Load Methods
87
+ #---------------------------------------------------------------
88
+
89
+ # Loads this entire environment, setting up the instance variables
90
+ # such as `vm`, `config`, etc. on this environment. The order this
91
+ # method calls its other methods is very particular.
92
+ def load!
93
+ load_root_path!
94
+ load_config!
95
+ load_home_directory!
96
+ load_box!
97
+ load_config!
98
+ self.class.check_virtualbox!
99
+ load_vm!
100
+ load_ssh!
101
+ load_active_list!
102
+ load_commands!
103
+ self
104
+ end
105
+
106
+ # Loads the root path of this environment, given the starting
107
+ # directory (the "cwd" of this environment for lack of better words).
108
+ # This method allows an environment in `/foo` to be detected from
109
+ # `/foo/bar` (similar to how git works in subdirectories)
110
+ def load_root_path!(path=nil)
111
+ path = Pathname.new(File.expand_path(path || cwd))
112
+
113
+ # Stop if we're at the root.
114
+ return false if path.root?
115
+
116
+ file = "#{path}/#{ROOTFILE_NAME}"
117
+ if File.exist?(file)
118
+ @root_path = path.to_s
119
+ return true
120
+ end
121
+
122
+ load_root_path!(path.parent)
123
+ end
124
+
125
+ # Loads this environment's configuration and stores it in the {config}
126
+ # variable. The configuration loaded by this method is specified to
127
+ # this environment, meaning that it will use the given root directory
128
+ # to load the Vagrantfile into that context.
129
+ def load_config!
130
+ # Prepare load paths for config files
131
+ load_paths = [File.join(PROJECT_ROOT, "config", "default.rb")]
132
+ load_paths << File.join(box.directory, ROOTFILE_NAME) if box
133
+ load_paths << File.join(home_path, ROOTFILE_NAME) if home_path
134
+ load_paths << File.join(root_path, ROOTFILE_NAME) if root_path
135
+
136
+ # Clear out the old data
137
+ Config.reset!(self)
138
+
139
+ # Load each of the config files in order
140
+ load_paths.each do |path|
141
+ if File.exist?(path)
142
+ logger.info "Loading config from #{path}..."
143
+ load path
144
+ end
145
+ end
146
+
147
+ # Execute the configuration stack and store the result
148
+ @config = Config.execute!
149
+ end
150
+
151
+ # Loads the home directory path and creates the necessary subdirectories
152
+ # within the home directory if they're not already created.
153
+ def load_home_directory!
154
+ # Setup the array of necessary home directories
155
+ dirs = HOME_SUBDIRS.collect { |subdir| File.join(home_path, subdir) }
156
+ dirs.unshift(home_path)
157
+
158
+ # Go through each required directory, creating it if it doesn't exist
159
+ dirs.each do |dir|
160
+ next if File.directory?(dir)
161
+
162
+ logger.info "Creating home directory since it doesn't exist: #{dir}"
163
+ FileUtils.mkdir_p(dir)
164
+ end
165
+ end
166
+
167
+ # Loads the specified box for this environment.
168
+ def load_box!
169
+ return unless root_path
170
+
171
+ @box = Box.find(self, config.vm.box) if config.vm.box
172
+ end
173
+
174
+ # Loads the persisted VM (if it exists) for this environment.
175
+ def load_vm!
176
+ return if !root_path || !File.file?(dotfile_path)
177
+
178
+ File.open(dotfile_path) do |f|
179
+ @vm = Vagrant::VM.find(f.read)
180
+ @vm.env = self if @vm
181
+ end
182
+ rescue Errno::ENOENT
183
+ @vm = nil
184
+ end
185
+
186
+ # Loads/initializes the SSH object
187
+ def load_ssh!
188
+ @ssh = SSH.new(self)
189
+ end
190
+
191
+ # Loads the activelist for this environment
192
+ def load_active_list!
193
+ @active_list = ActiveList.new(self)
194
+ end
195
+
196
+ # Loads the instance of {Commands} for this environment. This allows
197
+ # users of the instance to run commands such as "up" "down" etc. in
198
+ # the context of this environment.
199
+ def load_commands!
200
+ @commands = Commands.new(self)
201
+ end
202
+
203
+ #---------------------------------------------------------------
204
+ # Methods to manage VM
205
+ #---------------------------------------------------------------
206
+
207
+ # Sets the VM to a new VM. This is not too useful but is used
208
+ # in {Command.up}. This will very likely be refactored at a later
209
+ # time.
210
+ def create_vm
211
+ @vm = VM.new
212
+ @vm.env = self
213
+ @vm
214
+ end
215
+
216
+ # Persists this environment's VM to the dotfile so it can be
217
+ # re-loaded at a later time.
218
+ def persist_vm
219
+ # Save to the dotfile for this project
220
+ File.open(dotfile_path, 'w+') do |f|
221
+ f.write(vm.uuid)
222
+ end
223
+
224
+ # Also add to the global store
225
+ active_list.add(vm)
226
+ end
227
+
228
+ # Removes this environment's VM from the dotfile.
229
+ def depersist_vm
230
+ # Delete the dotfile if it exists
231
+ File.delete(dotfile_path) if File.exist?(dotfile_path)
232
+
233
+ # Remove from the global store
234
+ active_list.remove(vm)
235
+ end
236
+
237
+ #---------------------------------------------------------------
238
+ # Methods to check for properties and error
239
+ #---------------------------------------------------------------
240
+
241
+ def require_root_path
242
+ error_and_exit(:rootfile_not_found) if !root_path
243
+ end
244
+
245
+ def require_box
246
+ require_root_path
247
+
248
+ if !box
249
+ if !Vagrant.config.vm.box
250
+ error_and_exit(:box_not_specified)
251
+ else
252
+ error_and_exit(:box_specified_doesnt_exist, :box_name => Vagrant.config.vm.box)
253
+ end
254
+ end
255
+ end
256
+
257
+ def require_persisted_vm
258
+ require_root_path
259
+
260
+ error_and_exit(:environment_not_created) if !vm
261
+ end
262
+ end
263
+ end