vagrant-vbguest-update 0.10.1.dev

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 (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/CHANGELOG.md +209 -0
  4. data/Gemfile +11 -0
  5. data/LICENSE +21 -0
  6. data/Rakefile +11 -0
  7. data/Readme.md +267 -0
  8. data/lib/vagrant-vbguest.rb +57 -0
  9. data/lib/vagrant-vbguest/command.rb +95 -0
  10. data/lib/vagrant-vbguest/config.rb +51 -0
  11. data/lib/vagrant-vbguest/core_ext/string/interpolate.rb +110 -0
  12. data/lib/vagrant-vbguest/download.rb +28 -0
  13. data/lib/vagrant-vbguest/errors.rb +18 -0
  14. data/lib/vagrant-vbguest/hosts/base.rb +118 -0
  15. data/lib/vagrant-vbguest/hosts/virtualbox.rb +103 -0
  16. data/lib/vagrant-vbguest/installer.rb +121 -0
  17. data/lib/vagrant-vbguest/installers/base.rb +201 -0
  18. data/lib/vagrant-vbguest/installers/debian.rb +40 -0
  19. data/lib/vagrant-vbguest/installers/linux.rb +158 -0
  20. data/lib/vagrant-vbguest/installers/redhat.rb +29 -0
  21. data/lib/vagrant-vbguest/installers/ubuntu.rb +44 -0
  22. data/lib/vagrant-vbguest/machine.rb +105 -0
  23. data/lib/vagrant-vbguest/middleware.rb +43 -0
  24. data/lib/vagrant-vbguest/rebootable.rb +39 -0
  25. data/lib/vagrant-vbguest/vagrant_compat.rb +21 -0
  26. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_0/command.rb +17 -0
  27. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_0/download.rb +51 -0
  28. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_0/rebootable.rb +23 -0
  29. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_0/vm_compatible.rb +31 -0
  30. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_1/command.rb +18 -0
  31. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_1/download.rb +1 -0
  32. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_1/rebootable.rb +33 -0
  33. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_1/vm_compatible.rb +31 -0
  34. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_2/command.rb +1 -0
  35. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_2/download.rb +18 -0
  36. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_2/rebootable.rb +1 -0
  37. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_2/vm_compatible.rb +15 -0
  38. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_3/command.rb +1 -0
  39. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_3/download.rb +1 -0
  40. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_3/rebootable.rb +1 -0
  41. data/lib/vagrant-vbguest/vagrant_compat/vagrant_1_3/vm_compatible.rb +1 -0
  42. data/lib/vagrant-vbguest/version.rb +3 -0
  43. data/lib/vagrant_init.rb +38 -0
  44. data/locales/en.yml +63 -0
  45. data/vagrant-vbguest.gemspec +30 -0
  46. metadata +161 -0
@@ -0,0 +1,103 @@
1
+ module VagrantVbguest
2
+ module Hosts
3
+ class VirtualBox < Base
4
+
5
+ protected
6
+
7
+ # Default web URI, where GuestAdditions iso file can be downloaded.
8
+ #
9
+ # @return [String] A URI template containing the versions placeholder.
10
+ def web_path
11
+ "http://download.virtualbox.org/virtualbox/%{version}/VBoxGuestAdditions_%{version}.iso"
12
+ end
13
+
14
+
15
+ # Finds GuestAdditions iso file on the host system.
16
+ # Returns +nil+ if none found.
17
+ #
18
+ # @return [String] Absolute path to the local GuestAdditions iso file, or +nil+ if not found.
19
+ def local_path
20
+ media_manager_iso || guess_local_iso
21
+ end
22
+
23
+ # Kicks off +VagrantVbguest::Download+ to download the additions file
24
+ # into a temp file.
25
+ #
26
+ # To remove the created tempfile call +cleanup+
27
+ #
28
+ # @param [String] The path or URI to download
29
+ #
30
+ # @return [String] The path to the downloaded file
31
+ def download(path)
32
+ temp_path = File.join(@env.tmp_path, "VBoxGuestAdditions_#{version}.iso")
33
+ @download = VagrantVbguest::Download.new(path, temp_path, :ui => @env.ui)
34
+ @download.download!
35
+ @download.destination
36
+ end
37
+
38
+ private
39
+
40
+ # Helper method which queries the VirtualBox media manager
41
+ # for the first existing path that looks like a
42
+ # +VBoxGuestAdditions.iso+ file.
43
+ #
44
+ # @return [String] Absolute path to the local GuestAdditions iso file, or +nil+ if not found.
45
+ def media_manager_iso
46
+ driver.execute('list', 'dvds').scan(/^.+:\s+(.*VBoxGuestAdditions(?:_#{version})?\.iso)$/i).map { |path, _|
47
+ path if File.exist?(path)
48
+ }.compact.first
49
+ end
50
+
51
+ # Find the first GuestAdditions iso file which exists on the host system
52
+ #
53
+ # @return [String] Absolute path to the local GuestAdditions iso file, or +nil+ if not found.
54
+ def guess_local_iso
55
+ Array(platform_path).find do |path|
56
+ path && File.exists?(path)
57
+ end
58
+ end
59
+
60
+ # Makes an educated guess where the GuestAdditions iso file
61
+ # could be found on the host system depending on the OS.
62
+ # Returns +nil+ if no the file is not in it's place.
63
+ def platform_path
64
+ [:linux, :darwin, :cygwin, :windows].each do |sys|
65
+ return self.send("#{sys}_path") if Vagrant::Util::Platform.respond_to?("#{sys}?") && Vagrant::Util::Platform.send("#{sys}?")
66
+ end
67
+ nil
68
+ end
69
+
70
+ # Makes an educated guess where the GuestAdditions iso file
71
+ # on linux based systems
72
+ def linux_path
73
+ paths = ["/usr/share/virtualbox/VBoxGuestAdditions.iso"]
74
+ paths.unshift(File.join(ENV['HOME'], '.VirtualBox', "VBoxGuestAdditions_#{version}.iso")) if ENV['HOME']
75
+ paths
76
+ end
77
+
78
+ # Makes an educated guess where the GuestAdditions iso file
79
+ # on Macs
80
+ def darwin_path
81
+ "/Applications/VirtualBox.app/Contents/MacOS/VBoxGuestAdditions.iso"
82
+ end
83
+
84
+ # Makes an educated guess where the GuestAdditions iso file
85
+ # on windows systems
86
+ def windows_path
87
+ if (p = ENV["VBOX_INSTALL_PATH"]) && !p.empty?
88
+ File.join(p, "VBoxGuestAdditions.iso")
89
+ elsif (p = ENV["PROGRAM_FILES"] || ENV["ProgramW6432"] || ENV["PROGRAMFILES"]) && !p.empty?
90
+ File.join(p, "/Oracle/VirtualBox/VBoxGuestAdditions.iso")
91
+ end
92
+ end
93
+ alias_method :cygwin_path, :windows_path
94
+
95
+ # overwrite the default version string to allow lagacy
96
+ # '$VBOX_VERSION' as a placerholder
97
+ def versionize(path)
98
+ super(path.gsub('$VBOX_VERSION', version))
99
+ end
100
+
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,121 @@
1
+ module VagrantVbguest
2
+
3
+ ##
4
+ # Dispatches the installation process to a rigistered
5
+ # Installer implementation.
6
+ class Installer
7
+
8
+ class NoInstallerFoundError < Vagrant::Errors::VagrantError
9
+ error_namespace "vagrant_vbguest.errors.installer"
10
+ error_key "no_installer_for_platform"
11
+ end
12
+
13
+ class << self
14
+
15
+ ##
16
+ # Register an Installer implementation.
17
+ # All Installer classes which wish to get picked automaticly
18
+ # using their `#match?` method have to register.
19
+ # Ad-hoc or small custom Installer meight not need to get
20
+ # registered, but need to get passed as an config option (`installer`)
21
+ #
22
+ # Registration takes a priority which defines how specific
23
+ # the Installer matches a system. Low level installers, like
24
+ # "linux" or "bsd" use a small priority (2), while distribution
25
+ # installers use higher priority (5). Installers matching a
26
+ # specific version of a distribution should use heigher
27
+ # priority numbers.
28
+ #
29
+ # @param [Class] installer_class A reference to the Installer class.
30
+ # @param [Fixnum] prio Priority describing how specific the Installer matches. (default: `5`)
31
+ def register(installer_class, prio = 5)
32
+ @installers ||= {}
33
+ @installers[prio] ||= []
34
+ @installers[prio] << installer_class
35
+ end
36
+
37
+ ##
38
+ # Returns the class of the registrated Installer class which
39
+ # matches first (according to it's priority) or `nil` if none matches.
40
+ def detect(vm, options)
41
+ @installers.keys.sort.reverse.each do |prio|
42
+ klass = @installers[prio].detect { |k| k.match?(vm) }
43
+ return klass if klass
44
+ end
45
+ return nil
46
+ end
47
+ end
48
+
49
+ def initialize(vm, options = {})
50
+ @vm = vm
51
+ @env = vm.env
52
+ @options = options
53
+ @iso_path = nil
54
+ end
55
+
56
+ def install
57
+ installer = guest_installer
58
+ raise NoInstallerFoundError, :method => 'install' if !installer
59
+
60
+ installer.install do |type, data|
61
+ @env.ui.info(data, :prefix => false, :new_line => false)
62
+ end
63
+ ensure
64
+ cleanup
65
+ end
66
+
67
+ def rebuild
68
+ installer = guest_installer
69
+ raise NoInstallerFoundError, :method => 'rebuild' if !installer
70
+
71
+ installer.rebuild do |type, data|
72
+ @env.ui.info(data, :prefix => false, :new_line => false)
73
+ end
74
+ end
75
+
76
+ def start
77
+ installer = guest_installer
78
+ raise NoInstallerFoundError, :method => 'manual start' if !installer
79
+
80
+ installer.start do |type, data|
81
+ @env.ui.info(data, :prefix => false, :new_line => false)
82
+ end
83
+ end
84
+
85
+ def guest_version(reload=false)
86
+ installer = guest_installer
87
+ raise NoInstallerFoundError, :method => 'check guest version of' if !installer
88
+ installer.guest_version(reload)
89
+ end
90
+
91
+ def host_version
92
+ installer = guest_installer
93
+ raise NoInstallerFoundError, :method => 'check host version of' if !installer
94
+ installer.host.version
95
+ end
96
+
97
+ def running?
98
+ installer = guest_installer
99
+ raise NoInstallerFoundError, :method => 'check current state of' if !installer
100
+ installer.running?
101
+ end
102
+
103
+ # Returns an installer instance for the current vm
104
+ # This is either the one configured via `installer` option or
105
+ # detected from all registered installers (see {Installer.detect})
106
+ #
107
+ # @return [Installers::Base]
108
+ def guest_installer
109
+ @guest_installer ||= if @options[:installer].is_a? Class
110
+ @options[:installer].new(@vm, @options)
111
+ else
112
+ installer_klass = Installer.detect(@vm, @options) and installer_klass.new(@vm, @options)
113
+ end
114
+ end
115
+
116
+ def cleanup
117
+ @guest_installer.cleanup if @guest_installer
118
+ end
119
+
120
+ end
121
+ end
@@ -0,0 +1,201 @@
1
+ module VagrantVbguest
2
+ module Installers
3
+ class Error < Vagrant::Errors::VagrantError
4
+ error_namespace "vagrant_vbguest.errors.installer"
5
+ end
6
+
7
+ # This is the base class all installers must inherit from
8
+ # It defines the basic structure of an Installer and should
9
+ # never be used directly
10
+ class Base
11
+ include VagrantVbguest::Helpers::VmCompatible
12
+
13
+ # Tests whether this installer class is applicable to the
14
+ # current environment. Usually, testing for a specific OS.
15
+ # Subclasses must override this method and return `true` if
16
+ # they wish to handle.
17
+ #
18
+ # This method will be called only when an Installer detection
19
+ # is run. It is ignored, when passing an Installer class
20
+ # directly as an config (`installer`) option.
21
+ #
22
+ # @param [Vagrant::VM]
23
+ # @return [Boolean]
24
+ def self.match?(vm)
25
+ false
26
+ end
27
+
28
+ attr_reader :env, :vm, :options, :host
29
+
30
+ def initialize(vm, options=nil)
31
+ @vm = vm
32
+ @env = vm.env
33
+ @options = options
34
+
35
+ @host = VagrantVbguest::Hosts::VirtualBox.new(vm, options)
36
+ end
37
+
38
+ # The absolute file path of the GuestAdditions iso file should
39
+ # be uploaded into the guest.
40
+ # Subclasses must override this method!
41
+ #
42
+ # @return [String]
43
+ def tmp_path
44
+ end
45
+
46
+ # The mountpoint path
47
+ # Subclasses shall override this method, if they need to mount the uploaded file!
48
+ #
49
+ # @return [String]
50
+ def mount_point
51
+ end
52
+
53
+ # Handles the installation process.
54
+ # All necessary steps for an installation must be defined here.
55
+ # This includes uploading the iso into the box, mounting,
56
+ # installing and cleaning up.
57
+ # The path to the local iso file should be obtained by calling +iso_file+
58
+ # Subclasses must override this method!
59
+ #
60
+ # @param [Hash] opts Optional options Hash wich meight get passed to {Vagrant::Communication::SSH#execute} and firends
61
+ # @yield [type, data] Takes a Block like {Vagrant::Communication::Base#execute} for realtime output of the command being executed
62
+ # @yieldparam [String] type Type of the output, `:stdout`, `:stderr`, etc.
63
+ # @yieldparam [String] data Data for the given output.
64
+ def install(opts=nil, &block)
65
+ end
66
+
67
+ # Handels the rebuild of allready running GuestAdditions
68
+ # It may happen, that the guest has the correct GuestAdditions
69
+ # version running, but not the kernel module is not running.
70
+ # This method should perform a rebuild or try to reload the
71
+ # kernel module _without_ the GuestAdditions iso file.
72
+ # If there is no way of rebuidling or reloading the
73
+ # GuestAdditions on a specific system, this method should left
74
+ # empty.
75
+ # Subclasses should override this method.
76
+ #
77
+ # @param [Hash] opts Optional options Hash wich meight get passed to {Vagrant::Communication::SSH#execute} and firends
78
+ # @yield [type, data] Takes a Block like {Vagrant::Communication::Base#execute} for realtime output of the command being executed
79
+ # @yieldparam [String] type Type of the output, `:stdout`, `:stderr`, etc.
80
+ # @yieldparam [String] data Data for the given output.
81
+ def rebuild(opts=nil, &block)
82
+ end
83
+
84
+ # Restarts the allready installed GuestAdditions
85
+ # It may happen, that the guest has the correct GuestAdditions
86
+ # version installed, but for some reason are not (yet) runnig.
87
+ # This method should execute the GuestAdditions system specific
88
+ # init script in order to start it manually.
89
+ # If there is no way of doing this on a specific system,
90
+ # this method should left empty.
91
+ # Subclasses should override this method.
92
+ #
93
+ # @param [Hash] opts Optional options Hash wich meight get passed to {Vagrant::Communication::SSH#execute} and firends
94
+ # @yield [type, data] Takes a Block like {Vagrant::Communication::Base#execute} for realtime output of the command being executed
95
+ # @yieldparam [String] type Type of the output, `:stdout`, `:stderr`, etc.
96
+ # @yieldparam [String] data Data for the given output.
97
+ def start(opts=nil, &block)
98
+ end
99
+
100
+ # Determinates if the GuestAdditions kernel module is loaded.
101
+ # This method tests if there is a working GuestAdditions
102
+ # kernel module. If there is none, {#rebuild} is beeing called.
103
+ # If there is no way of telling if there is a working
104
+ # GuestAddition for a specific system, this method should
105
+ # return `true`.
106
+ # Subclasses should override this method.
107
+ #
108
+ # @return [Boolean] `true` if the kernel module is loaded (and thus seems to work), `false` otherwise.
109
+ def running?(opts=nil, &block)
110
+ true
111
+ end
112
+
113
+ # Determinates the GuestAdditions version installed on the
114
+ # guest system.
115
+ #
116
+ # @param [Boolean] reload Whether to read the value again or use
117
+ # the cached value form an erlier call.
118
+ # @return [String] The version code of the VirtualBox Guest Additions
119
+ # available on the guest, or `nil` if none installed.
120
+ def guest_version(reload=false)
121
+ return @guest_version if @guest_version && !reload
122
+
123
+ guest_version = driver.read_guest_additions_version
124
+ guest_version = !guest_version ? nil : guest_version.gsub(/[-_]ose/i, '')
125
+
126
+ @guest_version = guest_version
127
+ end
128
+
129
+
130
+ # Determinates the version of the GuestAdditions installer in use
131
+ #
132
+ # @return [String] The version code of the GuestAdditions installer
133
+ def installer_version(path_to_installer)
134
+ version = nil
135
+ communicate.sudo("#{path_to_installer} --info", :error_check => false) do |type, data|
136
+ if (v = data.to_s.match(/\AIdentification.*\s(\d+\.\d+.\d+)/i))
137
+ version = v[1]
138
+ end
139
+ end
140
+ version
141
+ end
142
+
143
+ # Helper to yield a warning message to the user, that the installation
144
+ # will start _now_.
145
+ # The message includes the host and installer version strings.
146
+ def yield_installation_waring(path_to_installer)
147
+ @env.ui.warn I18n.t("vagrant_vbguest.installing#{@options[:force] ? '_forced' : ''}",
148
+ :guest_version => guest_version,
149
+ :installer_version => installer_version(path_to_installer) || I18n.t("vagrant_vbguest.unknown"))
150
+ end
151
+
152
+ # Helper to yield a warning message to the user, that the installation
153
+ # will be rebuild using the installed GuestAdditions.
154
+ # The message includes the host and installer version strings.
155
+ def yield_rebuild_warning
156
+ @env.ui.warn I18n.t("vagrant_vbguest.rebuild#{@options[:force] ? '_forced' : ''}",
157
+ :guest_version => guest_version(true),
158
+ :host_version => @host.version)
159
+ end
160
+
161
+ # Helper to yield a warning message to the user in the event that the
162
+ # installer returned a non-zero exit status. Because lack of a window
163
+ # system will cause this result in VirtualBox 4.2.8+, we don't want to
164
+ # kill the entire boot process, but we do want to make sure the user
165
+ # knows there could be a problem. The message includles the installer
166
+ # version.
167
+ def yield_installation_error_warning(path_to_installer)
168
+ @env.ui.warn I18n.t("vagrant_vbguest.install_error",
169
+ :installer_version => installer_version(path_to_installer) || I18n.t("vagrant_vbguest.unknown"))
170
+ end
171
+
172
+ def iso_file
173
+ @host.additions_file
174
+ end
175
+ alias_method :additions_file, :iso_file
176
+
177
+ # A helper method to handle the GuestAdditions iso file upload
178
+ # into the guest box.
179
+ # The file will uploaded to the location given by the +temp_path+ method.
180
+ #
181
+ # @example Default upload
182
+ # upload(file)
183
+ #
184
+ # @param [String] Path of the file to upload to the +tmp_path*
185
+ def upload(file)
186
+ env.ui.info(I18n.t("vagrant_vbguest.start_copy_iso", :from => file, :to => tmp_path))
187
+ communicate.upload(file, tmp_path)
188
+ end
189
+
190
+ # A helper method to delete the uploaded GuestAdditions iso file
191
+ # from the guest box
192
+ def cleanup
193
+ @host.cleanup
194
+ communicate.execute("test -f #{tmp_path} && rm #{tmp_path}", :error_check => false) do |type, data|
195
+ env.ui.error(data.chomp, :prefix => false)
196
+ end
197
+ end
198
+
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,40 @@
1
+ module VagrantVbguest
2
+ module Installers
3
+ class Debian < Linux
4
+
5
+ def self.match?(vm)
6
+ :debian == self.distro(vm)
7
+ end
8
+
9
+ # installes the correct linux-headers package
10
+ # installes `dkms` package for dynamic kernel module loading
11
+ # @param [Hash] opts Optional options Hash wich meight get passed to {Vagrant::Communication::SSH#execute} and firends
12
+ # @yield [type, data] Takes a Block like {Vagrant::Communication::Base#execute} for realtime output of the command being executed
13
+ # @yieldparam [String] type Type of the output, `:stdout`, `:stderr`, etc.
14
+ # @yieldparam [String] data Data for the given output.
15
+ def install(opts=nil, &block)
16
+ begin
17
+ communicate.sudo(install_dependencies_cmd, opts, &block)
18
+ rescue
19
+ communicate.sudo('apt-get update', opts, &block)
20
+ communicate.sudo(install_dependencies_cmd, opts, &block)
21
+ end
22
+ super
23
+ end
24
+
25
+ protected
26
+ def install_dependencies_cmd
27
+ "apt-get install -y #{dependencies}"
28
+ end
29
+
30
+ def dependencies
31
+ packages = ['linux-headers-`uname -r`']
32
+ # some Debian system (lenny) dont come with a dkms packe so we neet to skip that.
33
+ # apt-cache search will exit with 0 even if nothing was found, so we need to grep.
34
+ packages << 'dkms' if communicate.test('apt-cache search --names-only \'^dkms$\' | grep dkms')
35
+ packages.join ' '
36
+ end
37
+ end
38
+ end
39
+ end
40
+ VagrantVbguest::Installer.register(VagrantVbguest::Installers::Debian, 5)