From 52f3847b0af83f42cfb9eb3f0ba0c510c0923c06 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 21:47:57 -0700 Subject: [PATCH 01/24] Laying the foundation for the new guest plugin --- lib/vagrant/errors.rb | 4 ++ lib/vagrant/guest.rb | 101 ++++++++++++++++++++++++++++ lib/vagrant/machine.rb | 28 +------- lib/vagrant/plugin/v2/components.rb | 6 ++ lib/vagrant/plugin/v2/guest.rb | 40 ++++------- lib/vagrant/plugin/v2/manager.rb | 2 +- lib/vagrant/plugin/v2/plugin.rb | 15 ++--- plugins/guests/arch/guest.rb | 4 ++ plugins/guests/arch/plugin.rb | 2 +- plugins/guests/debian/guest.rb | 4 ++ plugins/guests/debian/plugin.rb | 2 +- plugins/guests/fedora/guest.rb | 4 ++ plugins/guests/fedora/plugin.rb | 2 +- plugins/guests/freebsd/guest.rb | 5 ++ plugins/guests/gentoo/guest.rb | 4 ++ plugins/guests/gentoo/plugin.rb | 2 +- plugins/guests/linux/guest.rb | 5 ++ plugins/guests/openbsd/guest.rb | 5 ++ plugins/guests/openbsd/plugin.rb | 2 +- plugins/guests/pld/guest.rb | 4 ++ plugins/guests/pld/plugin.rb | 2 +- plugins/guests/redhat/guest.rb | 4 ++ plugins/guests/redhat/plugin.rb | 2 +- plugins/guests/solaris/guest.rb | 4 ++ plugins/guests/suse/guest.rb | 4 ++ plugins/guests/suse/plugin.rb | 2 +- plugins/guests/ubuntu/guest.rb | 4 ++ plugins/guests/ubuntu/plugin.rb | 2 +- templates/locales/en.yml | 18 ++--- test/unit/vagrant/guest_test.rb | 75 +++++++++++++++++++++ test/unit/vagrant/machine_test.rb | 55 ++------------- 31 files changed, 281 insertions(+), 132 deletions(-) create mode 100644 lib/vagrant/guest.rb create mode 100644 test/unit/vagrant/guest_test.rb diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb index 084d66c84..9db88ceb6 100644 --- a/lib/vagrant/errors.rb +++ b/lib/vagrant/errors.rb @@ -227,6 +227,10 @@ module Vagrant error_key(:port_collision_resume) end + class GuestNotDetected < VagrantError + error_key(:guest_not_detected) + end + class LocalDataDirectoryNotAccessible < VagrantError error_key(:local_data_dir_not_accessible) end diff --git a/lib/vagrant/guest.rb b/lib/vagrant/guest.rb new file mode 100644 index 000000000..52dcd3e21 --- /dev/null +++ b/lib/vagrant/guest.rb @@ -0,0 +1,101 @@ +require "log4r" + +module Vagrant + # This class handles guest-OS specific interactions with a machine. + # It is primarily responsible for detecting the proper guest OS + # implementation and then delegating capabilities. + # + # Vagrant has many tasks which require specific guest OS knowledge. + # These are implemented using a guest/capability system. Various plugins + # register as "guests" which determine the underlying OS of the system. + # Then, "guest capabilities" register themselves for a specific OS (one + # or more), and these capabilities are called. + # + # Example capabilities might be "mount_virtualbox_shared_folder" or + # "configure_networks". + # + # This system allows for maximum flexibility and pluginability for doing + # guest OS specific operations. + class Guest + attr_reader :chain + + def initialize(machine, guests) + @logger = Log4r::Logger.new("vagrant::guest") + @chain = [] + @guests = guests + @machine = machine + end + + # This will detect the proper guest OS for the machine and set up + # the class to actually execute capabilities. + def detect! + @logger.info("Detect guest for machine: #{@machine}") + + # Get the mapping of guests with the most parents. We start searching + # with the guests with the most parents first. + parent_count = {} + @guests.each do |name, parts| + parent_count[name] = 0 + + parent = parts[1] + while parent + parent_count[name] += 1 + parent = @guests[parent] + parent = parent[1] if parent + end + end + + # Now swap around the mapping so that it is a mapping of + # count to the actual list of guest names + parent_count_to_guests = {} + parent_count.each do |name, count| + parent_count_to_guests[count] ||= [] + parent_count_to_guests[count] << name + end + + catch(:guest_os) do + sorted_counts = parent_count_to_guests.keys.sort.reverse + sorted_counts.each do |count| + parent_count_to_guests[count].each do |name| + @logger.debug("Trying: #{name}") + guest_info = @guests[name] + guest = guest_info[0].new + + if guest.detect?(@machine) + @logger.info("Detected: #{name}!") + @chain << guest + + # Build the proper chain of parents if there are any. + # This allows us to do "inheritence" of capabilities later + if guest_info[1] + parent_info = @guests[guest_info[1]] + while parent_info + @chain << parent_info[0].new + parent_info = @guests[parent_info[1]] + end + end + + @logger.info("Full guest chain: #{@chain.inspect}") + + # Exit the search + throw :guest_os + end + end + end + end + + # We shouldn't reach this point. Ideally we would detect + # all operating systems. + raise Errors::GuestNotDetected if @chain.empty? + end + + # This returns whether the guest is ready to work. If this returns + # `false`, then {#detect!} should be called in order to detect the + # guest OS. + # + # @return [Boolean] + def ready? + !@chain.empty? + end + end +end diff --git a/lib/vagrant/machine.rb b/lib/vagrant/machine.rb index f8be78aef..0b12580b1 100644 --- a/lib/vagrant/machine.rb +++ b/lib/vagrant/machine.rb @@ -83,6 +83,7 @@ module Vagrant @config = config @data_dir = data_dir @env = env + @guest = Guest.new(self) @name = name @provider_config = provider_config @provider_name = provider_name @@ -169,32 +170,7 @@ module Vagrant # @return [Object] def guest raise Errors::MachineGuestNotReady if !communicate.ready? - - # Load the initial guest. - last_guest = config.vm.guest - guest = load_guest(last_guest) - - # Loop and distro dispatch while there are distros. - while true - distro = guest.distro_dispatch - break if !distro - - # This is just some really basic loop detection and avoiding for - # guest classes. This is just here to help implementers a bit - # avoid a situation that is fairly easy, since if you subclass - # a parent which does `distro_dispatch`, you'll end up dispatching - # forever. - if distro == last_guest - @logger.warn("Distro dispatch loop in '#{distro}'. Exiting loop.") - break - end - - last_guest = distro - guest = load_guest(distro) - end - - # Return the result - guest + @guest end # This sets the unique ID associated with this machine. This will diff --git a/lib/vagrant/plugin/v2/components.rb b/lib/vagrant/plugin/v2/components.rb index 9510b0a87..636f7ae6c 100644 --- a/lib/vagrant/plugin/v2/components.rb +++ b/lib/vagrant/plugin/v2/components.rb @@ -16,6 +16,11 @@ module Vagrant # @return [Hash] attr_reader :configs + # This contains all the guests and their parents. + # + # @return [Registry>] + attr_reader :guests + # This contains all the provider plugins by name, and returns # the provider class and options. # @@ -27,6 +32,7 @@ module Vagrant @action_hooks = Hash.new { |h, k| h[k] = [] } @configs = Hash.new { |h, k| h[k] = Registry.new } + @guests = Registry.new @providers = Registry.new end end diff --git a/lib/vagrant/plugin/v2/guest.rb b/lib/vagrant/plugin/v2/guest.rb index f757296dd..9af83887b 100644 --- a/lib/vagrant/plugin/v2/guest.rb +++ b/lib/vagrant/plugin/v2/guest.rb @@ -1,35 +1,21 @@ module Vagrant module Plugin module V2 - # The base class for a guest. A guest represents an installed system - # within a machine that Vagrant manages. There are some portions of - # Vagrant which are OS-specific such as mountaing shared folders and - # halting the machine, and this abstraction allows the implementation - # for these to be seperate from the core of Vagrant. + # A base class for a guest OS. A guest OS is responsible for detecting + # that the guest operating system running within the machine. The guest + # can then be extended with various "guest capabilities" which are their + # own form of plugin. + # + # The guest class itself is only responsible for detecting itself, + # and may provide helpers for the capabilties. class Guest - class BaseError < Errors::VagrantError - error_namespace("vagrant.guest.base") - end - - include Vagrant::Util - - # The VM which this system is tied to. - attr_reader :vm - - # Initializes the system. Any subclasses MUST make sure this - # method is called on the parent. Therefore, if a subclass overrides - # `initialize`, then you must call `super`. - def initialize(vm) - @vm = vm - end - - # This method is automatically called when the system is available (when - # Vagrant can successfully SSH into the machine) to give the system a chance - # to determine the distro and return a distro-specific system. + # This method is called when the machine is booted and has communication + # capabilities in order to detect whether this guest operating system + # is running within the machine. # - # If this method returns nil, then this instance is assumed to be - # the most specific guest implementation. - def distro_dispatch + # @return [Boolean] + def guest?(machine) + false end # Halt the machine. This method should gracefully shut down the diff --git a/lib/vagrant/plugin/v2/manager.rb b/lib/vagrant/plugin/v2/manager.rb index f7cfa5c4e..887bd5c0e 100644 --- a/lib/vagrant/plugin/v2/manager.rb +++ b/lib/vagrant/plugin/v2/manager.rb @@ -67,7 +67,7 @@ module Vagrant def guests Registry.new.tap do |result| @registered.each do |plugin| - result.merge!(plugin.guest) + result.merge!(plugin.components.guests) end end end diff --git a/lib/vagrant/plugin/v2/plugin.rb b/lib/vagrant/plugin/v2/plugin.rb index be2d11802..0480631fc 100644 --- a/lib/vagrant/plugin/v2/plugin.rb +++ b/lib/vagrant/plugin/v2/plugin.rb @@ -124,7 +124,6 @@ module Vagrant # without breaking anything in future versions of Vagrant. # # @param [String] name Configuration key. - # XXX: Document options hash def self.config(name, scope=nil, &block) scope ||= :top components.configs[scope].register(name.to_sym, &block) @@ -135,14 +134,14 @@ module Vagrant # the given key. # # @param [String] name Name of the guest. - def self.guest(name=UNSET_VALUE, &block) - data[:guests] ||= Registry.new + # @param [String] parent Name of the parent guest (if any) + def self.guest(name=UNSET_VALUE, parent=nil, &block) + components.guests.register(name.to_sym) do + parent = parent.to_sym if parent - # Register a new guest class only if a name was given - data[:guests].register(name.to_sym, &block) if name != UNSET_VALUE - - # Return the registry - data[:guests] + [block.call, parent] + end + nil end # Defines an additionally available host implementation with diff --git a/plugins/guests/arch/guest.rb b/plugins/guests/arch/guest.rb index 7b0b5f373..a354f6799 100644 --- a/plugins/guests/arch/guest.rb +++ b/plugins/guests/arch/guest.rb @@ -12,6 +12,10 @@ module VagrantPlugins # Make the TemplateRenderer top-level include Vagrant::Util + def detect?(machine) + machine.communicate.test("cat /etc/arch-release") + end + def change_host_name(name) # Only do this if the hostname is not already set if !vm.communicate.test("sudo hostname | grep '#{name}'") diff --git a/plugins/guests/arch/plugin.rb b/plugins/guests/arch/plugin.rb index bcbb945ae..36c2d76ce 100644 --- a/plugins/guests/arch/plugin.rb +++ b/plugins/guests/arch/plugin.rb @@ -6,7 +6,7 @@ module VagrantPlugins name "Arch guest" description "Arch guest support." - guest("arch") do + guest("arch", "linux") do require File.expand_path("../guest", __FILE__) Guest end diff --git a/plugins/guests/debian/guest.rb b/plugins/guests/debian/guest.rb index c5a32cb19..2712b32c7 100644 --- a/plugins/guests/debian/guest.rb +++ b/plugins/guests/debian/guest.rb @@ -12,6 +12,10 @@ module VagrantPlugins # Make the TemplateRenderer top-level include Vagrant::Util + def detect?(machine) + machine.communicate.test("cat /proc/version | grep 'Debian'") + end + def configure_networks(networks) # First, remove any previous network modifications # from the interface file. diff --git a/plugins/guests/debian/plugin.rb b/plugins/guests/debian/plugin.rb index 7cb276635..b9190d4bf 100644 --- a/plugins/guests/debian/plugin.rb +++ b/plugins/guests/debian/plugin.rb @@ -6,7 +6,7 @@ module VagrantPlugins name "Debian guest" description "Debian guest support." - guest("debian") do + guest("debian", "linux") do require File.expand_path("../guest", __FILE__) Guest end diff --git a/plugins/guests/fedora/guest.rb b/plugins/guests/fedora/guest.rb index 54856a3f5..f32d8f3d2 100644 --- a/plugins/guests/fedora/guest.rb +++ b/plugins/guests/fedora/guest.rb @@ -12,6 +12,10 @@ module VagrantPlugins # Make the TemplateRenderer top-level include Vagrant::Util + def detect?(machine) + machine.communicate.test("grep 'Fedora release 1[678]' /etc/redhat-release") + end + def configure_networks(networks) # Accumulate the configurations to add to the interfaces file as well # as what interfaces we're actually configuring since we use that later. diff --git a/plugins/guests/fedora/plugin.rb b/plugins/guests/fedora/plugin.rb index 29323f188..73bbcb911 100644 --- a/plugins/guests/fedora/plugin.rb +++ b/plugins/guests/fedora/plugin.rb @@ -6,7 +6,7 @@ module VagrantPlugins name "Fedora guest" description "Fedora guest support." - guest("fedora") do + guest("fedora", "linux") do require File.expand_path("../guest", __FILE__) Guest end diff --git a/plugins/guests/freebsd/guest.rb b/plugins/guests/freebsd/guest.rb index 7a3b5ea66..c5ff14951 100644 --- a/plugins/guests/freebsd/guest.rb +++ b/plugins/guests/freebsd/guest.rb @@ -11,6 +11,11 @@ module VagrantPlugins error_namespace("vagrant.guest.freebsd") end + def detect?(machine) + # TODO: FreeBSD detection + false + end + def halt begin vm.communicate.sudo("shutdown -p now") diff --git a/plugins/guests/gentoo/guest.rb b/plugins/guests/gentoo/guest.rb index 2f59dbd2c..5aaacd573 100644 --- a/plugins/guests/gentoo/guest.rb +++ b/plugins/guests/gentoo/guest.rb @@ -11,6 +11,10 @@ module VagrantPlugins # Make the TemplateRenderer top-level include Vagrant::Util + def detect?(machine) + machine.communicate.test("cat /etc/gentoo-release") + end + def configure_networks(networks) # Remove any previous host only network additions to the interface file vm.communicate.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/conf.d/net > /tmp/vagrant-network-interfaces") diff --git a/plugins/guests/gentoo/plugin.rb b/plugins/guests/gentoo/plugin.rb index c888d811d..b37b39565 100644 --- a/plugins/guests/gentoo/plugin.rb +++ b/plugins/guests/gentoo/plugin.rb @@ -6,7 +6,7 @@ module VagrantPlugins name "Gentoo guest" description "Gentoo guest support." - guest("gentoo") do + guest("gentoo", "linux") do require File.expand_path("../guest", __FILE__) Guest end diff --git a/plugins/guests/linux/guest.rb b/plugins/guests/linux/guest.rb index 7c649be92..f0bc77c1d 100644 --- a/plugins/guests/linux/guest.rb +++ b/plugins/guests/linux/guest.rb @@ -18,6 +18,11 @@ module VagrantPlugins @logger = Log4r::Logger.new("vagrant::guest::linux") end + def detect?(machine) + # TODO: Linux detection + false + end + def distro_dispatch @vm.communicate.tap do |comm| if comm.test("cat /etc/debian_version") diff --git a/plugins/guests/openbsd/guest.rb b/plugins/guests/openbsd/guest.rb index dd4a4831a..8a4e6408d 100644 --- a/plugins/guests/openbsd/guest.rb +++ b/plugins/guests/openbsd/guest.rb @@ -5,6 +5,11 @@ require Vagrant.source_root.join("plugins/guests/linux/guest") module VagrantPlugins module GuestOpenBSD class Guest < VagrantPlugins::GuestLinux::Guest + def detect?(machine) + # TODO: OpenBSD detection + false + end + def halt vm.communicate.sudo("shutdown -p -h now") end diff --git a/plugins/guests/openbsd/plugin.rb b/plugins/guests/openbsd/plugin.rb index ce74391c0..dd6f38a76 100644 --- a/plugins/guests/openbsd/plugin.rb +++ b/plugins/guests/openbsd/plugin.rb @@ -6,7 +6,7 @@ module VagrantPlugins name "OpenBSD guest" description "OpenBSD guest support." - guest("openbsd") do + guest("openbsd", "linux") do require File.expand_path("../guest", __FILE__) Guest end diff --git a/plugins/guests/pld/guest.rb b/plugins/guests/pld/guest.rb index b183102a4..a2d7ad881 100644 --- a/plugins/guests/pld/guest.rb +++ b/plugins/guests/pld/guest.rb @@ -5,6 +5,10 @@ require Vagrant.source_root.join("plugins/guests/redhat/guest") module VagrantPlugins module GuestPld class Guest < VagrantPlugins::GuestRedHat::Guest + def detect?(machine) + machine.communicate.test("cat /etc/pld-release") + end + def network_scripts_dir '/etc/sysconfig/interfaces/' end diff --git a/plugins/guests/pld/plugin.rb b/plugins/guests/pld/plugin.rb index b072ed9f6..bd457b8c1 100644 --- a/plugins/guests/pld/plugin.rb +++ b/plugins/guests/pld/plugin.rb @@ -6,7 +6,7 @@ module VagrantPlugins name "PLD Linux guest" description "PLD Linux guest support." - guest("pld") do + guest("pld", "redhat") do require File.expand_path("../guest", __FILE__) Guest end diff --git a/plugins/guests/redhat/guest.rb b/plugins/guests/redhat/guest.rb index 39c508856..0ac990ea0 100644 --- a/plugins/guests/redhat/guest.rb +++ b/plugins/guests/redhat/guest.rb @@ -12,6 +12,10 @@ module VagrantPlugins # Make the TemplateRenderer top-level include Vagrant::Util + def detect?(machine) + machine.communicate.test("cat /etc/redhat-release") + end + def configure_networks(networks) # Accumulate the configurations to add to the interfaces file as # well as what interfaces we're actually configuring since we use that diff --git a/plugins/guests/redhat/plugin.rb b/plugins/guests/redhat/plugin.rb index 4355152ff..dd80ef78f 100644 --- a/plugins/guests/redhat/plugin.rb +++ b/plugins/guests/redhat/plugin.rb @@ -6,7 +6,7 @@ module VagrantPlugins name "RedHat guest" description "RedHat guest support." - guest("redhat") do + guest("redhat", "linux") do require File.expand_path("../guest", __FILE__) Guest end diff --git a/plugins/guests/solaris/guest.rb b/plugins/guests/solaris/guest.rb index a5f13c92e..a815748d0 100644 --- a/plugins/guests/solaris/guest.rb +++ b/plugins/guests/solaris/guest.rb @@ -11,6 +11,10 @@ module VagrantPlugins error_namespace("vagrant.guest.solaris") end + def detect?(machine) + machine.communicate.test("grep 'Solaris' /etc/release") + end + def configure_networks(networks) networks.each do |network| device = "#{vm.config.solaris.device}#{network[:interface]}" diff --git a/plugins/guests/suse/guest.rb b/plugins/guests/suse/guest.rb index 8694b669e..e6caeda45 100644 --- a/plugins/guests/suse/guest.rb +++ b/plugins/guests/suse/guest.rb @@ -5,6 +5,10 @@ require Vagrant.source_root.join("plugins/guests/redhat/guest") module VagrantPlugins module GuestSuse class Guest < VagrantPlugins::GuestRedHat::Guest + def detect?(machine) + machine.communicate.test("cat /etc/SuSE-release") + end + def network_scripts_dir '/etc/sysconfig/network/' end diff --git a/plugins/guests/suse/plugin.rb b/plugins/guests/suse/plugin.rb index 12e925f02..0fd401ea7 100644 --- a/plugins/guests/suse/plugin.rb +++ b/plugins/guests/suse/plugin.rb @@ -6,7 +6,7 @@ module VagrantPlugins name "SUSE guest" description "SUSE guest support." - guest("suse") do + guest("suse", "redhat") do require File.expand_path("../guest", __FILE__) Guest end diff --git a/plugins/guests/ubuntu/guest.rb b/plugins/guests/ubuntu/guest.rb index bc199b535..707f2e8fa 100644 --- a/plugins/guests/ubuntu/guest.rb +++ b/plugins/guests/ubuntu/guest.rb @@ -5,6 +5,10 @@ require Vagrant.source_root.join("plugins/guests/debian/guest") module VagrantPlugins module GuestUbuntu class Guest < VagrantPlugins::GuestDebian::Guest + def detect?(machine) + machine.communicate.test("cat /proc/version | grep 'Ubuntu'") + end + def mount_shared_folder(name, guestpath, options) # Mount it like normal super diff --git a/plugins/guests/ubuntu/plugin.rb b/plugins/guests/ubuntu/plugin.rb index 8e3cc72c1..f8e5c0708 100644 --- a/plugins/guests/ubuntu/plugin.rb +++ b/plugins/guests/ubuntu/plugin.rb @@ -6,7 +6,7 @@ module VagrantPlugins name "Ubuntu guest" description "Ubuntu guest support." - guest("ubuntu") do + guest("ubuntu", "debian") do require File.expand_path("../guest", __FILE__) Guest end diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 832fb2701..ea5ae4d1d 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -173,18 +173,12 @@ en: of the official installers or another gem is wrongly attempting to use Vagrant internals directly. Please properly install Vagrant to fix this. If this error persists, please contact support. - guest: - invalid_class: |- - The specified guest class does not inherit from a proper guest - component class. The guest class must inherit from this. - - The specified guest class was: %{guest} - unknown_type: |- - The specified guest type is unknown: %{guest}. Please change this - to a proper value. - unspecified: |- - A VM guest type must be specified! This is done via the `config.vm.guest` - configuration value. Please read the documentation online for more information. + guest_not_detected: |- + The guest operating system of the machine could not be detected! + Vagrant requires this knowledge to perform specific tasks such + as mounting shared folders and configuring networks. Please add + the ability to detect this guest operating system to Vagrant + by creating a plugin or reporting a bug. home_dir_not_accessible: |- The home directory you specified is not accessible. The home directory that Vagrant uses must be both readable and writable. diff --git a/test/unit/vagrant/guest_test.rb b/test/unit/vagrant/guest_test.rb new file mode 100644 index 000000000..0cff98738 --- /dev/null +++ b/test/unit/vagrant/guest_test.rb @@ -0,0 +1,75 @@ +require "pathname" + +require File.expand_path("../../base", __FILE__) + +describe Vagrant::Guest do + include_context "unit" + + let(:guests) { {} } + let(:machine) { double("machine") } + + subject { described_class.new(machine, guests) } + + # This registers a guest with the class. + # + # @param [Symbol] name Name of the guest + # @param [Symbol] parent Name of the parent + # @param [Boolean] detect Whether or not to detect properly + def register_guest(name, parent, detect) + guest = Class.new(Vagrant.plugin("2", "guest")) do + define_method(:name) do + name + end + + define_method(:detect?) do |m| + detect + end + end + + guests[name] = [guest, parent] + end + + describe "#detect!" do + it "detects the first match" do + register_guest(:foo, nil, false) + register_guest(:bar, nil, true) + register_guest(:baz, nil, false) + + subject.detect! + subject.chain.length.should == 1 + subject.chain[0].name.should == :bar + end + + it "detects those with the most parents first" do + register_guest(:foo, nil, true) + register_guest(:bar, :foo, true) + register_guest(:baz, :bar, true) + register_guest(:foo2, nil, true) + register_guest(:bar2, :foo2, true) + + subject.detect! + subject.chain.length.should == 3 + subject.chain.map(&:name).should == [:baz, :bar, :foo] + end + + it "raises an exception if no guest can be detected" do + expect { subject.detect! }. + to raise_error(Vagrant::Errors::GuestNotDetected) + end + end + + describe "#ready?" do + before(:each) do + register_guest(:foo, nil, true) + end + + it "should not be ready by default" do + subject.ready?.should_not be + end + + it "should be ready after detecting" do + subject.detect! + subject.ready?.should be + end + end +end diff --git a/test/unit/vagrant/machine_test.rb b/test/unit/vagrant/machine_test.rb index 7a24be9ab..74cdb51c1 100644 --- a/test/unit/vagrant/machine_test.rb +++ b/test/unit/vagrant/machine_test.rb @@ -197,6 +197,7 @@ describe Vagrant::Machine do let(:communicator) do result = double("communicator") result.stub(:ready?).and_return(true) + result.stub(:test).and_return(false) result end @@ -212,63 +213,19 @@ describe Vagrant::Machine do end it "should return the configured guest" do - test_guest = Class.new(Vagrant.plugin("2", :guest)) + test_guest = Class.new(Vagrant.plugin("2", :guest)) do + def detect?(machine) + true + end + end register_plugin do |p| p.guest(:test) { test_guest } end - config.vm.guest = :test - result = instance.guest result.should be_kind_of(test_guest) end - - it "should raise an exception if it can't find the configured guest" do - config.vm.guest = :bad - - expect { instance.guest }. - to raise_error(Vagrant::Errors::VMGuestError) - end - - it "should distro dispatch to the most specific guest" do - # Create the classes and dispatch the parent into the child - guest_parent = Class.new(Vagrant.plugin("2", :guest)) do - def distro_dispatch - :child - end - end - - guest_child = Class.new(Vagrant.plugin("2", :guest)) - - # Register the classes - register_plugin do |p| - p.guest(:parent) { guest_parent } - p.guest(:child) { guest_child } - end - - # Test that the result is the child - config.vm.guest = :parent - instance.guest.should be_kind_of(guest_child) - end - - it "should protect against loops in the distro dispatch" do - # Create the classes and dispatch the parent into the child - guest_parent = Class.new(Vagrant.plugin("2", :guest)) do - def distro_dispatch - :parent - end - end - - # Register the classes - register_plugin do |p| - p.guest(:parent) { guest_parent } - end - - # Test that the result is the child - config.vm.guest = :parent - instance.guest.should be_kind_of(guest_parent) - end end describe "setting the ID" do From 06a9968ec4fc74245ff58f316e183dc0ab8c2051 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 22:03:03 -0700 Subject: [PATCH 02/24] Guest#capability? for testing for capabilities --- lib/vagrant/guest.rb | 41 +++++++++++++++++++------ test/unit/vagrant/guest_test.rb | 53 +++++++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 12 deletions(-) diff --git a/lib/vagrant/guest.rb b/lib/vagrant/guest.rb index 52dcd3e21..2a36ea3e6 100644 --- a/lib/vagrant/guest.rb +++ b/lib/vagrant/guest.rb @@ -19,11 +19,19 @@ module Vagrant class Guest attr_reader :chain - def initialize(machine, guests) - @logger = Log4r::Logger.new("vagrant::guest") - @chain = [] - @guests = guests - @machine = machine + # The name of the guest OS. This is available after {#detect!} is + # called. + # + # @return [Symbol] + attr_reader :name + + def initialize(machine, guests, capabilities) + @logger = Log4r::Logger.new("vagrant::guest") + @capabilities = capabilities + @chain = [] + @guests = guests + @machine = machine + @name = nil end # This will detect the proper guest OS for the machine and set up @@ -63,15 +71,18 @@ module Vagrant if guest.detect?(@machine) @logger.info("Detected: #{name}!") - @chain << guest + @chain << [name, guest] + @name = name # Build the proper chain of parents if there are any. # This allows us to do "inheritence" of capabilities later if guest_info[1] - parent_info = @guests[guest_info[1]] + parent_name = guest_info[1] + parent_info = @guests[parent_name] while parent_info - @chain << parent_info[0].new - parent_info = @guests[parent_info[1]] + @chain << [parent_name, parent_info[0].new] + parent_name = parent_info[1] + parent_info = @guests[parent_name] end end @@ -89,6 +100,18 @@ module Vagrant raise Errors::GuestNotDetected if @chain.empty? end + # Tests whether the guest has the named capability. + # + # @return [Boolean] + def capability?(cap_name) + @chain.each do |guest_name, guest| + caps = @capabilities[guest_name] + return true if caps && caps.has_key?(cap_name) + end + + false + end + # This returns whether the guest is ready to work. If this returns # `false`, then {#detect!} should be called in order to detect the # guest OS. diff --git a/test/unit/vagrant/guest_test.rb b/test/unit/vagrant/guest_test.rb index 0cff98738..228c19360 100644 --- a/test/unit/vagrant/guest_test.rb +++ b/test/unit/vagrant/guest_test.rb @@ -5,10 +5,22 @@ require File.expand_path("../../base", __FILE__) describe Vagrant::Guest do include_context "unit" + let(:capabilities) { {} } let(:guests) { {} } let(:machine) { double("machine") } - subject { described_class.new(machine, guests) } + subject { described_class.new(machine, guests, capabilities) } + + # This registers a capability with a specific guest + def register_capability(guest, capability) + cap = Class.new do + define_method(capability) do + end + end + + capabilities[guest] ||= {} + capabilities[guest][capability] = cap.new + end # This registers a guest with the class. # @@ -29,6 +41,37 @@ describe Vagrant::Guest do guests[name] = [guest, parent] end + describe "#capability?" do + before :each do + register_guest(:foo, nil, true) + register_guest(:bar, :foo, true) + + subject.detect! + end + + it "doesn't have unknown capabilities" do + subject.capability?(:what_is_this_i_dont_even).should_not be + end + + it "doesn't have capabilities registered to other guests" do + register_capability(:baz, :test) + + subject.capability?(:test).should_not be + end + + it "has capability of detected guest" do + register_capability(:bar, :test) + + subject.capability?(:test).should be + end + + it "has capability of parent guests" do + register_capability(:foo, :test) + + subject.capability?(:test).should be + end + end + describe "#detect!" do it "detects the first match" do register_guest(:foo, nil, false) @@ -36,8 +79,10 @@ describe Vagrant::Guest do register_guest(:baz, nil, false) subject.detect! + subject.name.should == :bar subject.chain.length.should == 1 - subject.chain[0].name.should == :bar + subject.chain[0][0].should == :bar + subject.chain[0][1].name.should == :bar end it "detects those with the most parents first" do @@ -48,8 +93,10 @@ describe Vagrant::Guest do register_guest(:bar2, :foo2, true) subject.detect! + subject.name.should == :baz subject.chain.length.should == 3 - subject.chain.map(&:name).should == [:baz, :bar, :foo] + subject.chain.map(&:first).should == [:baz, :bar, :foo] + subject.chain.map { |x| x[1] }.map(&:name).should == [:baz, :bar, :foo] end it "raises an exception if no guest can be detected" do From cf3c1b73d24218a63dbcca9f7c53e917d75c34f9 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 22:19:20 -0700 Subject: [PATCH 03/24] Guest#capability to execute capabilities --- lib/vagrant/errors.rb | 8 +++++++ lib/vagrant/guest.rb | 41 +++++++++++++++++++++++++++++---- templates/locales/en.yml | 11 +++++++++ test/unit/vagrant/guest_test.rb | 37 +++++++++++++++++++++++++++-- 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb index 9db88ceb6..b90d4277e 100644 --- a/lib/vagrant/errors.rb +++ b/lib/vagrant/errors.rb @@ -227,6 +227,14 @@ module Vagrant error_key(:port_collision_resume) end + class GuestCapabilityInvalid < VagrantError + error_key(:guest_capability_invalid) + end + + class GuestCapabilityNotFound < VagrantError + error_key(:guest_capability_not_found) + end + class GuestNotDetected < VagrantError error_key(:guest_not_detected) end diff --git a/lib/vagrant/guest.rb b/lib/vagrant/guest.rb index 2a36ea3e6..f13dc4885 100644 --- a/lib/vagrant/guest.rb +++ b/lib/vagrant/guest.rb @@ -104,12 +104,30 @@ module Vagrant # # @return [Boolean] def capability?(cap_name) - @chain.each do |guest_name, guest| - caps = @capabilities[guest_name] - return true if caps && caps.has_key?(cap_name) + !capability_module(cap_name).nil? + end + + # Executes the capability with the given name, optionally passing + # more arguments onwards to the capability. + def capability(cap_name) + @logger.info("Execute capability: #{cap_name} (#{@chain[0][0]})") + cap_mod = capability_module(cap_name) + if !cap_mod + raise Errors::GuestCapabilityNotFound, + :cap => cap_name.to_s, + :guest => @chain[0][0].to_s end - false + cap_method = nil + begin + cap_method = cap_mod.method(cap_name) + rescue NameError + raise Errors::GuestCapabilityInvalid, + :cap => cap_name.to_s, + :guest => @chain[0][0].to_s + end + + cap_method.call end # This returns whether the guest is ready to work. If this returns @@ -120,5 +138,20 @@ module Vagrant def ready? !@chain.empty? end + + protected + + # Returns the registered module for a capability with the given name. + # + # @param [Symbol] cap_name + # @return [Module] + def capability_module(cap_name) + @chain.each do |guest_name, guest| + caps = @capabilities[guest_name] + return caps[cap_name] if caps && caps.has_key?(cap_name) + end + + nil + end end end diff --git a/templates/locales/en.yml b/templates/locales/en.yml index ea5ae4d1d..9a70947e0 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -173,6 +173,17 @@ en: of the official installers or another gem is wrongly attempting to use Vagrant internals directly. Please properly install Vagrant to fix this. If this error persists, please contact support. + guest_capability_invalid: |- + The registered guest capability '%{cap}' for the + detected guest OS '%{guest}' is invalid. The capability does + not implement the proper method. This is a bug with Vagrant or the + plugin that implements this capability. Please report a bug. + guest_capability_not_found: |- + Vagrant attempted to execute the capability '%{cap}' + on the detect guest OS '%{guest}', but the guest doesn't + support that capability. This capability is required for your + configuration of Vagrant. Please either reconfigure Vagrant to + avoid this capability or fix the issue by creating the capability. guest_not_detected: |- The guest operating system of the machine could not be detected! Vagrant requires this knowledge to perform specific tasks such diff --git a/test/unit/vagrant/guest_test.rb b/test/unit/vagrant/guest_test.rb index 228c19360..f530e7046 100644 --- a/test/unit/vagrant/guest_test.rb +++ b/test/unit/vagrant/guest_test.rb @@ -12,9 +12,14 @@ describe Vagrant::Guest do subject { described_class.new(machine, guests, capabilities) } # This registers a capability with a specific guest - def register_capability(guest, capability) + def register_capability(guest, capability, options=nil) + options ||= {} + cap = Class.new do - define_method(capability) do + if !options[:corrupt] + define_method(capability) do + raise "cap: #{capability}" + end end end @@ -41,6 +46,34 @@ describe Vagrant::Guest do guests[name] = [guest, parent] end + describe "#capability" do + before :each do + register_guest(:foo, nil, true) + register_guest(:bar, :foo, true) + + subject.detect! + end + + it "executes the capability" do + register_capability(:bar, :test) + + expect { subject.capability(:test) }. + to raise_error(RuntimeError, "cap: test") + end + + it "raises an exception if the capability doesn't exist" do + expect { subject.capability(:what_is_this_i_dont_even) }. + to raise_error(Vagrant::Errors::GuestCapabilityNotFound) + end + + it "raises an exception if the method doesn't exist on the module" do + register_capability(:bar, :test_is_corrupt, corrupt: true) + + expect { subject.capability(:test_is_corrupt) }. + to raise_error(Vagrant::Errors::GuestCapabilityInvalid) + end + end + describe "#capability?" do before :each do register_guest(:foo, nil, true) From f48b0796a5f32dcca2d0063a3ccd0e3c36ff5793 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 22:20:45 -0700 Subject: [PATCH 04/24] Forward arguments down to capability --- lib/vagrant/guest.rb | 4 ++-- test/unit/vagrant/guest_test.rb | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/vagrant/guest.rb b/lib/vagrant/guest.rb index f13dc4885..be63ff3df 100644 --- a/lib/vagrant/guest.rb +++ b/lib/vagrant/guest.rb @@ -109,7 +109,7 @@ module Vagrant # Executes the capability with the given name, optionally passing # more arguments onwards to the capability. - def capability(cap_name) + def capability(cap_name, *args) @logger.info("Execute capability: #{cap_name} (#{@chain[0][0]})") cap_mod = capability_module(cap_name) if !cap_mod @@ -127,7 +127,7 @@ module Vagrant :guest => @chain[0][0].to_s end - cap_method.call + cap_method.call(*args) end # This returns whether the guest is ready to work. If this returns diff --git a/test/unit/vagrant/guest_test.rb b/test/unit/vagrant/guest_test.rb index f530e7046..454dce84e 100644 --- a/test/unit/vagrant/guest_test.rb +++ b/test/unit/vagrant/guest_test.rb @@ -17,8 +17,8 @@ describe Vagrant::Guest do cap = Class.new do if !options[:corrupt] - define_method(capability) do - raise "cap: #{capability}" + define_method(capability) do |*args| + raise "cap: #{capability} #{args.inspect}" end end end @@ -58,7 +58,14 @@ describe Vagrant::Guest do register_capability(:bar, :test) expect { subject.capability(:test) }. - to raise_error(RuntimeError, "cap: test") + to raise_error(RuntimeError, "cap: test []") + end + + it "executes the capability with arguments" do + register_capability(:bar, :test) + + expect { subject.capability(:test, 1) }. + to raise_error(RuntimeError, "cap: test [1]") end it "raises an exception if the capability doesn't exist" do From c5c15fdaa647f1e07636417e12afd31d17cc71d5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 22:40:30 -0700 Subject: [PATCH 05/24] Machine#guest returns the proper guest detected --- lib/vagrant/machine.rb | 6 +++++- lib/vagrant/plugin/v2/components.rb | 6 ++++++ lib/vagrant/plugin/v2/manager.rb | 15 +++++++++++++ lib/vagrant/plugin/v2/plugin.rb | 12 +++++++++++ test/unit/vagrant/machine_test.rb | 24 +++++++++++---------- test/unit/vagrant/plugin/v2/manager_test.rb | 6 +++--- test/unit/vagrant/plugin/v2/plugin_test.rb | 2 +- 7 files changed, 55 insertions(+), 16 deletions(-) diff --git a/lib/vagrant/machine.rb b/lib/vagrant/machine.rb index 0b12580b1..8d6e93761 100644 --- a/lib/vagrant/machine.rb +++ b/lib/vagrant/machine.rb @@ -83,7 +83,10 @@ module Vagrant @config = config @data_dir = data_dir @env = env - @guest = Guest.new(self) + @guest = Guest.new( + self, + Vagrant.plugin("2").manager.guests, + Vagrant.plugin("2").manager.guest_capabilities) @name = name @provider_config = provider_config @provider_name = provider_name @@ -170,6 +173,7 @@ module Vagrant # @return [Object] def guest raise Errors::MachineGuestNotReady if !communicate.ready? + @guest.detect! if !@guest.ready? @guest end diff --git a/lib/vagrant/plugin/v2/components.rb b/lib/vagrant/plugin/v2/components.rb index 636f7ae6c..6b585d071 100644 --- a/lib/vagrant/plugin/v2/components.rb +++ b/lib/vagrant/plugin/v2/components.rb @@ -21,6 +21,11 @@ module Vagrant # @return [Registry>] attr_reader :guests + # This contains all the registered guest capabilities. + # + # @return [Hash] + attr_reader :guest_capabilities + # This contains all the provider plugins by name, and returns # the provider class and options. # @@ -33,6 +38,7 @@ module Vagrant @configs = Hash.new { |h, k| h[k] = Registry.new } @guests = Registry.new + @guest_capabilities = Hash.new { |h, k| h[k] = Registry.new } @providers = Registry.new end end diff --git a/lib/vagrant/plugin/v2/manager.rb b/lib/vagrant/plugin/v2/manager.rb index 887bd5c0e..b6e79e427 100644 --- a/lib/vagrant/plugin/v2/manager.rb +++ b/lib/vagrant/plugin/v2/manager.rb @@ -72,6 +72,21 @@ module Vagrant end end + # This returns all the registered guest capabilities. + # + # @return [Hash] + def guest_capabilities + results = Hash.new { |h, k| h[k] = Registry.new } + + @registered.each do |plugin| + plugin.components.guest_capabilities.each do |guest, caps| + results[guest].merge!(caps) + end + end + + results + end + # This returns all registered host classes. # # @return [Hash] diff --git a/lib/vagrant/plugin/v2/plugin.rb b/lib/vagrant/plugin/v2/plugin.rb index 0480631fc..e66da1b8b 100644 --- a/lib/vagrant/plugin/v2/plugin.rb +++ b/lib/vagrant/plugin/v2/plugin.rb @@ -144,6 +144,18 @@ module Vagrant nil end + # Defines a capability for the given guest. The block should return + # a class/module that has a method with the capability name, ready + # to be executed. This means that if it is an instance method, + # the block should return an instance of the class. + # + # @param [String] guest The name of the guest + # @param [String] cap The name of the capability + def self.guest_capability(guest, cap, &block) + components.guest_capabilities[guest.to_sym].register(cap.to_sym, &block) + nil + end + # Defines an additionally available host implementation with # the given key. # diff --git a/test/unit/vagrant/machine_test.rb b/test/unit/vagrant/machine_test.rb index 74cdb51c1..287b49447 100644 --- a/test/unit/vagrant/machine_test.rb +++ b/test/unit/vagrant/machine_test.rb @@ -202,6 +202,16 @@ describe Vagrant::Machine do end before(:each) do + test_guest = Class.new(Vagrant.plugin("2", :guest)) do + def detect?(machine) + true + end + end + + register_plugin do |p| + p.guest(:test) { test_guest } + end + instance.stub(:communicate).and_return(communicator) end @@ -213,18 +223,10 @@ describe Vagrant::Machine do end it "should return the configured guest" do - test_guest = Class.new(Vagrant.plugin("2", :guest)) do - def detect?(machine) - true - end - end - - register_plugin do |p| - p.guest(:test) { test_guest } - end - result = instance.guest - result.should be_kind_of(test_guest) + result.should be_kind_of(Vagrant::Guest) + result.ready?.should be + result.chain[0][0].should == :test end end diff --git a/test/unit/vagrant/plugin/v2/manager_test.rb b/test/unit/vagrant/plugin/v2/manager_test.rb index 7ed9d751e..d669a05f1 100644 --- a/test/unit/vagrant/plugin/v2/manager_test.rb +++ b/test/unit/vagrant/plugin/v2/manager_test.rb @@ -92,15 +92,15 @@ describe Vagrant::Plugin::V2::Manager do end pB = plugin do |p| - p.guest("bar") { "baz" } + p.guest("bar", "foo") { "baz" } end instance.register(pA) instance.register(pB) instance.guests.to_hash.length.should == 2 - instance.guests[:foo].should == "bar" - instance.guests[:bar].should == "baz" + instance.guests[:foo].should == ["bar", nil] + instance.guests[:bar].should == ["baz", :foo] end it "should enumerate registered host classes" do diff --git a/test/unit/vagrant/plugin/v2/plugin_test.rb b/test/unit/vagrant/plugin/v2/plugin_test.rb index 7e0b88d84..c00a8d9ca 100644 --- a/test/unit/vagrant/plugin/v2/plugin_test.rb +++ b/test/unit/vagrant/plugin/v2/plugin_test.rb @@ -154,7 +154,7 @@ describe Vagrant::Plugin::V2::Plugin do guest("foo") { "bar" } end - plugin.guest[:foo].should == "bar" + plugin.components.guests[:foo].should == ["bar", nil] end it "should lazily register guest classes" do From 819ef46fcac58ff58b7a8f583d63a221cddae1f0 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 22:43:35 -0700 Subject: [PATCH 06/24] Tests for registering guest capabilities --- lib/vagrant/machine.rb | 2 +- test/unit/vagrant/plugin/v2/manager_test.rb | 17 +++++++++++++++++ test/unit/vagrant/plugin/v2/plugin_test.rb | 10 ++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/vagrant/machine.rb b/lib/vagrant/machine.rb index 8d6e93761..47b23d202 100644 --- a/lib/vagrant/machine.rb +++ b/lib/vagrant/machine.rb @@ -170,7 +170,7 @@ module Vagrant # knows how to do guest-OS specific tasks, such as configuring networks, # mounting folders, etc. # - # @return [Object] + # @return [Guest] def guest raise Errors::MachineGuestNotReady if !communicate.ready? @guest.detect! if !@guest.ready? diff --git a/test/unit/vagrant/plugin/v2/manager_test.rb b/test/unit/vagrant/plugin/v2/manager_test.rb index d669a05f1..d0ab6fd58 100644 --- a/test/unit/vagrant/plugin/v2/manager_test.rb +++ b/test/unit/vagrant/plugin/v2/manager_test.rb @@ -103,6 +103,23 @@ describe Vagrant::Plugin::V2::Manager do instance.guests[:bar].should == ["baz", :foo] end + it "should enumerate registered guest capabilities" do + pA = plugin do |p| + p.guest_capability("foo", "foo") { "bar" } + end + + pB = plugin do |p| + p.guest_capability("bar", "foo") { "baz" } + end + + instance.register(pA) + instance.register(pB) + + instance.guest_capabilities.length.should == 2 + instance.guest_capabilities[:foo][:foo].should == "bar" + instance.guest_capabilities[:bar][:foo].should == "baz" + end + it "should enumerate registered host classes" do pA = plugin do |p| p.host("foo") { "bar" } diff --git a/test/unit/vagrant/plugin/v2/plugin_test.rb b/test/unit/vagrant/plugin/v2/plugin_test.rb index c00a8d9ca..0295b3242 100644 --- a/test/unit/vagrant/plugin/v2/plugin_test.rb +++ b/test/unit/vagrant/plugin/v2/plugin_test.rb @@ -176,6 +176,16 @@ describe Vagrant::Plugin::V2::Plugin do end end + describe "guest capabilities" do + it "should register guest capabilities" do + plugin = Class.new(described_class) do + guest_capability("foo", "bar") { "baz" } + end + + plugin.components.guest_capabilities[:foo][:bar].should == "baz" + end + end + describe "hosts" do it "should register host classes" do plugin = Class.new(described_class) do From 28d3f274d816b8fcf83c8db5b7f5dbb88d8b3e3f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 23:01:43 -0700 Subject: [PATCH 07/24] First capability for linux --- lib/vagrant/guest.rb | 2 +- .../cap/mount_virtualbox_shared_folder.rb | 41 +++++++++++++++++++ .../linux/cap/shell_expand_guest_path.rb | 27 ++++++++++++ plugins/guests/linux/guest.rb | 29 ------------- plugins/guests/linux/plugin.rb | 10 +++++ .../virtualbox/action/share_folders.rb | 3 +- test/unit/vagrant/guest_test.rb | 10 +++-- 7 files changed, 88 insertions(+), 34 deletions(-) create mode 100644 plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb create mode 100644 plugins/guests/linux/cap/shell_expand_guest_path.rb diff --git a/lib/vagrant/guest.rb b/lib/vagrant/guest.rb index be63ff3df..5629af70f 100644 --- a/lib/vagrant/guest.rb +++ b/lib/vagrant/guest.rb @@ -127,7 +127,7 @@ module Vagrant :guest => @chain[0][0].to_s end - cap_method.call(*args) + cap_method.call(@machine, *args) end # This returns whether the guest is ready to work. If this returns diff --git a/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb b/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb new file mode 100644 index 000000000..127a673ea --- /dev/null +++ b/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb @@ -0,0 +1,41 @@ +module VagrantPlugins + module GuestLinux + module Cap + class MountVirtualBoxSharedFolder + def self.mount_virtualbox_shared_folder(machine, name, guestpath, options) + expanded_guest_path = machine.guest.capability( + :shell_expand_guest_path, guestpath) + + # Determine the permission string to attach to the mount command + mount_options = "-o uid=`id -u #{options[:owner]}`,gid=`id -g #{options[:group]}`" + mount_options += ",#{options[:extra]}" if options[:extra] + mount_command = "mount -t vboxsf #{mount_options} #{name} #{expanded_guest_path}" + + # Create the guest path if it doesn't exist + machine.communicate.sudo("mkdir -p #{expanded_guest_path}") + + # Attempt to mount the folder. We retry here a few times because + # it can fail early on. + attempts = 0 + while true + success = true + machine.communicate.sudo(mount_command) do |type, data| + success = false if type == :stderr && data =~ /No such device/i + end + + break if success + + attempts += 1 + # TODO: Nicer exception + raise "Mount failed" + sleep 2 + end + + # Chown the directory to the proper user + machine.communicate.sudo( + "chown `id -u #{options[:owner]}`:`id -g #{options[:group]}` #{expanded_guest_path}") + end + end + end + end +end diff --git a/plugins/guests/linux/cap/shell_expand_guest_path.rb b/plugins/guests/linux/cap/shell_expand_guest_path.rb new file mode 100644 index 000000000..1869ccfb3 --- /dev/null +++ b/plugins/guests/linux/cap/shell_expand_guest_path.rb @@ -0,0 +1,27 @@ +module VagrantPlugins + module GuestLinux + module Cap + class ShellExpandGuestPath + def self.shell_expand_guest_path(machine, path) + real_path = nil + machine.communicate.execute("printf #{guestpath}") do |type, data| + if type == :stdout + real_path ||= "" + real_path += data + end + end + + if !real_path + # If no real guest path was detected, this is really strange + # and we raise an exception because this is a bug. + # TODO: Nice exception + raise "No expanded guest path detected." + end + + # Chomp the string so that any trailing newlines are killed + return real_path.chomp + end + end + end + end +end diff --git a/plugins/guests/linux/guest.rb b/plugins/guests/linux/guest.rb index f0bc77c1d..bef17506f 100644 --- a/plugins/guests/linux/guest.rb +++ b/plugins/guests/linux/guest.rb @@ -52,15 +52,6 @@ module VagrantPlugins end end - def mount_shared_folder(name, guestpath, options) - real_guestpath = expanded_guest_path(guestpath) - @logger.debug("Shell expanded guest path: #{real_guestpath}") - - @vm.communicate.sudo("mkdir -p #{real_guestpath}") - mount_folder(name, real_guestpath, options) - @vm.communicate.sudo("chown `id -u #{options[:owner]}`:`id -g #{options[:group]}` #{real_guestpath}") - end - def mount_nfs(ip, folders) # TODO: Maybe check for nfs support on the guest, since its often # not installed by default @@ -105,26 +96,6 @@ module VagrantPlugins # Chomp the string so that any trailing newlines are killed return real_guestpath.chomp end - - def mount_folder(name, guestpath, options) - # Determine the permission string to attach to the mount command - mount_options = "-o uid=`id -u #{options[:owner]}`,gid=`id -g #{options[:group]}`" - mount_options += ",#{options[:extra]}" if options[:extra] - - attempts = 0 - while true - success = true - @vm.communicate.sudo("mount -t vboxsf #{mount_options} #{name} #{guestpath}") do |type, data| - success = false if type == :stderr && data =~ /No such device/i - end - - break if success - - attempts += 1 - raise LinuxError, :mount_fail if attempts >= 10 - sleep 5 - end - end end end end diff --git a/plugins/guests/linux/plugin.rb b/plugins/guests/linux/plugin.rb index 7c766edb5..ee0ce1065 100644 --- a/plugins/guests/linux/plugin.rb +++ b/plugins/guests/linux/plugin.rb @@ -15,6 +15,16 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("linux", "shell_expand_guest_path") do + require_relative "cap/shell_expand_guest_path" + Cap::ShellExpandGuestPath + end + + guest_capability("linux", "mount_virtualbox_shared_folder") do + require_relative "cap/mount_virtualbox_shared_folder" + Cap::MountVirtualBoxSharedFolder + end end end end diff --git a/plugins/providers/virtualbox/action/share_folders.rb b/plugins/providers/virtualbox/action/share_folders.rb index 9dd394c0c..e795a56ed 100644 --- a/plugins/providers/virtualbox/action/share_folders.rb +++ b/plugins/providers/virtualbox/action/share_folders.rb @@ -108,7 +108,8 @@ module VagrantPlugins data[:group] ||= @env[:machine].config.ssh.username # Mount the actual folder - @env[:machine].guest.mount_shared_folder(id, data[:guestpath], data) + @env[:machine].guest.capability( + :mount_virtualbox_shared_folder, id, data[:guestpath], data) else # If no guest path is specified, then automounting is disabled @env[:ui].info(I18n.t("vagrant.actions.vm.share_folders.nomount_entry", diff --git a/test/unit/vagrant/guest_test.rb b/test/unit/vagrant/guest_test.rb index 454dce84e..d778ccd05 100644 --- a/test/unit/vagrant/guest_test.rb +++ b/test/unit/vagrant/guest_test.rb @@ -7,7 +7,11 @@ describe Vagrant::Guest do let(:capabilities) { {} } let(:guests) { {} } - let(:machine) { double("machine") } + let(:machine) do + double("machine").tap do |m| + m.stub(:inspect => "machine") + end + end subject { described_class.new(machine, guests, capabilities) } @@ -58,14 +62,14 @@ describe Vagrant::Guest do register_capability(:bar, :test) expect { subject.capability(:test) }. - to raise_error(RuntimeError, "cap: test []") + to raise_error(RuntimeError, "cap: test [machine]") end it "executes the capability with arguments" do register_capability(:bar, :test) expect { subject.capability(:test, 1) }. - to raise_error(RuntimeError, "cap: test [1]") + to raise_error(RuntimeError, "cap: test [machine, 1]") end it "raises an exception if the capability doesn't exist" do From 2a542dab02f7f6505641d3b0f88cb82c6a90bd48 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 23:08:33 -0700 Subject: [PATCH 08/24] Switch configure_networks to capabilities system --- .../guests/debian/cap/configure_networks.rb | 58 +++++++++++++++++++ plugins/guests/debian/guest.rb | 45 -------------- plugins/guests/debian/plugin.rb | 5 ++ .../linux/cap/shell_expand_guest_path.rb | 2 +- .../providers/virtualbox/action/network.rb | 2 +- 5 files changed, 65 insertions(+), 47 deletions(-) create mode 100644 plugins/guests/debian/cap/configure_networks.rb diff --git a/plugins/guests/debian/cap/configure_networks.rb b/plugins/guests/debian/cap/configure_networks.rb new file mode 100644 index 000000000..dc949df5e --- /dev/null +++ b/plugins/guests/debian/cap/configure_networks.rb @@ -0,0 +1,58 @@ +require "vagrant/util/template_renderer" + +module VagrantPlugins + module GuestDebian + module Cap + class ConfigureNetworks + include Vagrant::Util + + def self.configure_networks(machine, networks) + machine.communicate.tap do |comm| + # First, remove any previous network modifications + # from the interface file. + comm.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/network/interfaces > /tmp/vagrant-network-interfaces") + comm.sudo("su -c 'cat /tmp/vagrant-network-interfaces > /etc/network/interfaces'") + comm.sudo("rm /tmp/vagrant-network-interfaces") + + # Accumulate the configurations to add to the interfaces file as + # well as what interfaces we're actually configuring since we use that + # later. + interfaces = Set.new + entries = [] + networks.each do |network| + interfaces.add(network[:interface]) + entry = TemplateRenderer.render("guests/debian/network_#{network[:type]}", + :options => network) + + entries << entry + end + + # Perform the careful dance necessary to reconfigure + # the network interfaces + temp = Tempfile.new("vagrant") + temp.binmode + temp.write(entries.join("\n")) + temp.close + + comm.upload(temp.path, "/tmp/vagrant-network-entry") + + # Bring down all the interfaces we're reconfiguring. By bringing down + # each specifically, we avoid reconfiguring eth0 (the NAT interface) so + # SSH never dies. + interfaces.each do |interface| + comm.sudo("/sbin/ifdown eth#{interface} 2> /dev/null") + end + + comm.sudo("cat /tmp/vagrant-network-entry >> /etc/network/interfaces") + comm.sudo("rm /tmp/vagrant-network-entry") + + # Bring back up each network interface, reconfigured + interfaces.each do |interface| + comm.sudo("/sbin/ifup eth#{interface}") + end + end + end + end + end + end +end diff --git a/plugins/guests/debian/guest.rb b/plugins/guests/debian/guest.rb index 2712b32c7..4dfb38a38 100644 --- a/plugins/guests/debian/guest.rb +++ b/plugins/guests/debian/guest.rb @@ -16,51 +16,6 @@ module VagrantPlugins machine.communicate.test("cat /proc/version | grep 'Debian'") end - def configure_networks(networks) - # First, remove any previous network modifications - # from the interface file. - vm.communicate.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/network/interfaces > /tmp/vagrant-network-interfaces") - vm.communicate.sudo("su -c 'cat /tmp/vagrant-network-interfaces > /etc/network/interfaces'") - vm.communicate.sudo("rm /tmp/vagrant-network-interfaces") - - # Accumulate the configurations to add to the interfaces file as - # well as what interfaces we're actually configuring since we use that - # later. - interfaces = Set.new - entries = [] - networks.each do |network| - interfaces.add(network[:interface]) - entry = TemplateRenderer.render("guests/debian/network_#{network[:type]}", - :options => network) - - entries << entry - end - - # Perform the careful dance necessary to reconfigure - # the network interfaces - temp = Tempfile.new("vagrant") - temp.binmode - temp.write(entries.join("\n")) - temp.close - - vm.communicate.upload(temp.path, "/tmp/vagrant-network-entry") - - # Bring down all the interfaces we're reconfiguring. By bringing down - # each specifically, we avoid reconfiguring eth0 (the NAT interface) so - # SSH never dies. - interfaces.each do |interface| - vm.communicate.sudo("/sbin/ifdown eth#{interface} 2> /dev/null") - end - - vm.communicate.sudo("cat /tmp/vagrant-network-entry >> /etc/network/interfaces") - vm.communicate.sudo("rm /tmp/vagrant-network-entry") - - # Bring back up each network interface, reconfigured - interfaces.each do |interface| - vm.communicate.sudo("/sbin/ifup eth#{interface}") - end - end - def change_host_name(name) vm.communicate.tap do |comm| if !comm.test("hostname --fqdn | grep '^#{name}$' || hostname --short | grep '^#{name}$'") diff --git a/plugins/guests/debian/plugin.rb b/plugins/guests/debian/plugin.rb index b9190d4bf..f0c9ccceb 100644 --- a/plugins/guests/debian/plugin.rb +++ b/plugins/guests/debian/plugin.rb @@ -10,6 +10,11 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("debian", "configure_networks") do + require_relative "cap/configure_networks" + Cap::ConfigureNetworks + end end end end diff --git a/plugins/guests/linux/cap/shell_expand_guest_path.rb b/plugins/guests/linux/cap/shell_expand_guest_path.rb index 1869ccfb3..23ee6174f 100644 --- a/plugins/guests/linux/cap/shell_expand_guest_path.rb +++ b/plugins/guests/linux/cap/shell_expand_guest_path.rb @@ -4,7 +4,7 @@ module VagrantPlugins class ShellExpandGuestPath def self.shell_expand_guest_path(machine, path) real_path = nil - machine.communicate.execute("printf #{guestpath}") do |type, data| + machine.communicate.execute("printf #{path}") do |type, data| if type == :stdout real_path ||= "" real_path += data diff --git a/plugins/providers/virtualbox/action/network.rb b/plugins/providers/virtualbox/action/network.rb index dca3000c9..736524eaa 100644 --- a/plugins/providers/virtualbox/action/network.rb +++ b/plugins/providers/virtualbox/action/network.rb @@ -112,7 +112,7 @@ module VagrantPlugins # Only configure the networks the user requested us to configure networks_to_configure = networks.select { |n| n[:auto_config] } env[:ui].info I18n.t("vagrant.actions.vm.network.configuring") - env[:machine].guest.configure_networks(networks_to_configure) + env[:machine].guest.capability(:configure_networks, networks_to_configure) end end From 63f28a90116574eb7d2fdcdc353633d616c03327 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 23:14:24 -0700 Subject: [PATCH 09/24] Nicer error messages for new linux caps --- lib/vagrant/errors.rb | 8 +++++ .../cap/mount_virtualbox_shared_folder.rb | 3 +- .../linux/cap/shell_expand_guest_path.rb | 3 +- plugins/guests/linux/guest.rb | 30 ------------------- templates/locales/en.yml | 13 +++++++- 5 files changed, 22 insertions(+), 35 deletions(-) diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb index b90d4277e..4c7c151ea 100644 --- a/lib/vagrant/errors.rb +++ b/lib/vagrant/errors.rb @@ -239,6 +239,14 @@ module Vagrant error_key(:guest_not_detected) end + class LinuxMountFailed < VagrantError + error_key(:linux_mount_failed) + end + + class LinuxShellExpandFailed < VagrantError + error_key(:linux_shell_expand_failed) + end + class LocalDataDirectoryNotAccessible < VagrantError error_key(:local_data_dir_not_accessible) end diff --git a/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb b/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb index 127a673ea..2b3fa026d 100644 --- a/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb +++ b/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb @@ -26,8 +26,7 @@ module VagrantPlugins break if success attempts += 1 - # TODO: Nicer exception - raise "Mount failed" + raise Vagrant::Errors::LinuxMountFailed, :command => mount_command sleep 2 end diff --git a/plugins/guests/linux/cap/shell_expand_guest_path.rb b/plugins/guests/linux/cap/shell_expand_guest_path.rb index 23ee6174f..983e366f0 100644 --- a/plugins/guests/linux/cap/shell_expand_guest_path.rb +++ b/plugins/guests/linux/cap/shell_expand_guest_path.rb @@ -14,8 +14,7 @@ module VagrantPlugins if !real_path # If no real guest path was detected, this is really strange # and we raise an exception because this is a bug. - # TODO: Nice exception - raise "No expanded guest path detected." + raise LinuxShellExpandFailed end # Chomp the string so that any trailing newlines are killed diff --git a/plugins/guests/linux/guest.rb b/plugins/guests/linux/guest.rb index bef17506f..0a9261277 100644 --- a/plugins/guests/linux/guest.rb +++ b/plugins/guests/linux/guest.rb @@ -8,41 +8,11 @@ module VagrantPlugins class Guest < Vagrant.plugin("2", :guest) include Vagrant::Util::Retryable - class LinuxError < Vagrant::Errors::VagrantError - error_namespace("vagrant.guest.linux") - end - - def initialize(*args) - super - - @logger = Log4r::Logger.new("vagrant::guest::linux") - end - def detect?(machine) # TODO: Linux detection false end - def distro_dispatch - @vm.communicate.tap do |comm| - if comm.test("cat /etc/debian_version") - return :debian if comm.test("cat /proc/version | grep 'Debian'") - return :ubuntu if comm.test("cat /proc/version | grep 'Ubuntu'") - end - - return :gentoo if comm.test("cat /etc/gentoo-release") - return :fedora if comm.test("grep 'Fedora release 1[678]' /etc/redhat-release") - return :redhat if comm.test("cat /etc/redhat-release") - return :suse if comm.test("cat /etc/SuSE-release") - return :pld if comm.test("cat /etc/pld-release") - return :arch if comm.test("cat /etc/arch-release") - return :solaris if comm.test("grep 'Solaris' /etc/release") - end - - # Can't detect the distro, assume vanilla linux - nil - end - def halt begin @vm.communicate.sudo("shutdown -h now") diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 9a70947e0..3c5f3034d 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -204,6 +204,18 @@ en: running Vagrant. Local data directory: %{local_data_path} + linux_mount_failed: |- + Failed to mount folders in Linux guest. This is usually beacuse + the "vboxsf" file system is not available. Please verify that + the guest additions are properly installed in the guest and + can work properly. The command attempted was: + + %{command} + linux_shell_expand_failed: |- + Vagrant failed to determine the shell expansion of the guest path + for one of your shared folders. This is an extremely rare error case + and most likely indicates an unusual configuration of the guest system. + Please report a bug with your Vagrantfile. machine_guest_not_ready: |- Guest-specific operations were attempted on a machine that is not ready for guest communication. This should not happen and a bug @@ -1066,7 +1078,6 @@ en: for one of your shared folders. This is an extremely rare error case and most likely indicates an unusual configuration of the guest system. Please report a bug with your Vagrantfile. - mount_fail: "Failed to mount shared folders. `vboxsf` was not available." mount_nfs_fail: |- Mounting NFS shared folders failed. This is most often caused by the NFS client software not being installed on the guest machine. Please verify From 511522e9ae79831a3fc994697d9f2d21ff8cde31 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 23:15:31 -0700 Subject: [PATCH 10/24] Remove unused keys --- templates/locales/en.yml | 43 ---------------------------------------- 1 file changed, 43 deletions(-) diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 3c5f3034d..44fd0e801 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -1034,50 +1034,7 @@ en: upload_path_not_set: "`upload_path` must be set for the shell provisioner." guest: - base: - unsupported_configure_networks: |- - Networking features require support that is dependent on the operating - system running within the guest virtual machine. Vagrant has built-in support - for many operating systems: Debian, Ubuntu, Gentoo, and RedHat. The distro - of your VM couldn't be detected or doesn't support networking features. - - Most of the time this is simply due to the fact that no one has contributed - back the logic necessary to set this up. Please report a bug as well as the - box you're using. - unsupported_host_name: |- - Setting host name is currently only supported on Debian, Ubuntu and RedHat. - If you'd like your guest OS to be supported, please open a ticket on the - project. - unsupported_nfs: |- - Vagrant doesn't support mounting NFS shared folders for your specific - guest operating system yet, or possibly couldn't properly detect the - operating system on the VM. - - Most of the time this is simply due to the fact that no one has contributed - back the logic necessary to set this up. Please report a bug as well as the - box you're using. - unsupported_halt: |- - Vagrant doesn't support graceful shutdowns for your specific - guest operating system yet, or possibly couldn't properly detect the - operating system on the VM. - - Most of the time this is simply due to the fact that no one has contributed - back the logic necessary to set this up. Please report a bug as well as the - box you're using. - unsupported_shared_folder: |- - Vagrant doesn't support mounting shared folders for your specific - guest operating system yet, or possibly couldn't properly detect the - operating system on the VM. - - Most of the time this is simply due to the fact that no one has contributed - back the logic necessary to set this up. Please report a bug as well as the - box you're using. linux: - guestpath_expand_fail: |- - Vagrant failed to determine the shell expansion of the guest path - for one of your shared folders. This is an extremely rare error case - and most likely indicates an unusual configuration of the guest system. - Please report a bug with your Vagrantfile. mount_nfs_fail: |- Mounting NFS shared folders failed. This is most often caused by the NFS client software not being installed on the guest machine. Please verify From 61d2f9f96fc0f0ef5869c732674f25c4ccc85c8c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 23:18:12 -0700 Subject: [PATCH 11/24] SetHostname uses new cap system --- lib/vagrant/action/builtin/set_hostname.rb | 2 +- plugins/guests/debian/cap/change_host_name.rb | 18 ++++++++++++++ .../guests/debian/cap/configure_networks.rb | 3 +++ plugins/guests/debian/guest.rb | 24 +------------------ plugins/guests/debian/plugin.rb | 5 ++++ 5 files changed, 28 insertions(+), 24 deletions(-) create mode 100644 plugins/guests/debian/cap/change_host_name.rb diff --git a/lib/vagrant/action/builtin/set_hostname.rb b/lib/vagrant/action/builtin/set_hostname.rb index 39f06bc4c..45458db0b 100644 --- a/lib/vagrant/action/builtin/set_hostname.rb +++ b/lib/vagrant/action/builtin/set_hostname.rb @@ -18,7 +18,7 @@ module Vagrant hostname = env[:machine].config.vm.hostname if !hostname.nil? env[:ui].info I18n.t("vagrant.actions.vm.hostname.setting") - env[:machine].guest.change_host_name(hostname) + env[:machine].guest.capability(:change_host_name, hostname) end end end diff --git a/plugins/guests/debian/cap/change_host_name.rb b/plugins/guests/debian/cap/change_host_name.rb new file mode 100644 index 000000000..6ce256d7e --- /dev/null +++ b/plugins/guests/debian/cap/change_host_name.rb @@ -0,0 +1,18 @@ +module VagrantPlugins + module GuestDebian + module Cap + class ChangeHostName + def self.change_host_name(machine, name) + machine.communicate.tap do |comm| + if !comm.test("hostname --fqdn | grep '^#{name}$' || hostname --short | grep '^#{name}$'") + comm.sudo("sed -r -i 's/^(127[.]0[.]1[.]1[[:space:]]+).*$/\\1#{name} #{name.split('.')[0]}/' /etc/hosts") + comm.sudo("sed -i 's/.*$/#{name.split('.')[0]}/' /etc/hostname") + comm.sudo("hostname -F /etc/hostname") + comm.sudo("hostname --fqdn > /etc/mailname") + end + end + end + end + end + end +end diff --git a/plugins/guests/debian/cap/configure_networks.rb b/plugins/guests/debian/cap/configure_networks.rb index dc949df5e..16e50158e 100644 --- a/plugins/guests/debian/cap/configure_networks.rb +++ b/plugins/guests/debian/cap/configure_networks.rb @@ -1,3 +1,6 @@ +require 'set' +require 'tempfile' + require "vagrant/util/template_renderer" module VagrantPlugins diff --git a/plugins/guests/debian/guest.rb b/plugins/guests/debian/guest.rb index 4dfb38a38..ec6b6a9a1 100644 --- a/plugins/guests/debian/guest.rb +++ b/plugins/guests/debian/guest.rb @@ -1,31 +1,9 @@ -require 'set' -require 'tempfile' - -require "vagrant" -require 'vagrant/util/template_renderer' - -require Vagrant.source_root.join("plugins/guests/linux/guest") - module VagrantPlugins module GuestDebian - class Guest < VagrantPlugins::GuestLinux::Guest - # Make the TemplateRenderer top-level - include Vagrant::Util - + class Guest < Vagrant.plugin("2", :guest) def detect?(machine) machine.communicate.test("cat /proc/version | grep 'Debian'") end - - def change_host_name(name) - vm.communicate.tap do |comm| - if !comm.test("hostname --fqdn | grep '^#{name}$' || hostname --short | grep '^#{name}$'") - comm.sudo("sed -r -i 's/^(127[.]0[.]1[.]1[[:space:]]+).*$/\\1#{name} #{name.split('.')[0]}/' /etc/hosts") - comm.sudo("sed -i 's/.*$/#{name.split('.')[0]}/' /etc/hostname") - comm.sudo("hostname -F /etc/hostname") - comm.sudo("hostname --fqdn > /etc/mailname") - end - end - end end end end diff --git a/plugins/guests/debian/plugin.rb b/plugins/guests/debian/plugin.rb index f0c9ccceb..45fc1544a 100644 --- a/plugins/guests/debian/plugin.rb +++ b/plugins/guests/debian/plugin.rb @@ -15,6 +15,11 @@ module VagrantPlugins require_relative "cap/configure_networks" Cap::ConfigureNetworks end + + guest_capability("debian", "change_host_name") do + require_relative "cap/change_host_name" + Cap::ChangeHostName + end end end end From 2f232e0175232c08fc0370d7ba40f264975e778b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 23:33:20 -0700 Subject: [PATCH 12/24] Halt and mount NFS are caps --- lib/vagrant/action/builtin/graceful_halt.rb | 2 +- lib/vagrant/action/builtin/nfs.rb | 3 +- lib/vagrant/errors.rb | 4 ++ plugins/guests/linux/cap/halt.rb | 16 ++++++ plugins/guests/linux/cap/mount_nfs.rb | 26 +++++++++ plugins/guests/linux/guest.rb | 59 --------------------- plugins/guests/linux/plugin.rb | 10 ++++ templates/locales/en.yml | 15 +++--- 8 files changed, 65 insertions(+), 70 deletions(-) create mode 100644 plugins/guests/linux/cap/halt.rb create mode 100644 plugins/guests/linux/cap/mount_nfs.rb diff --git a/lib/vagrant/action/builtin/graceful_halt.rb b/lib/vagrant/action/builtin/graceful_halt.rb index 832695ff4..da1235551 100644 --- a/lib/vagrant/action/builtin/graceful_halt.rb +++ b/lib/vagrant/action/builtin/graceful_halt.rb @@ -44,7 +44,7 @@ module Vagrant # checked above. if graceful env[:ui].info I18n.t("vagrant.actions.vm.halt.graceful") - env[:machine].guest.halt + env[:machine].guest.capability(:halt) @logger.debug("Waiting for target graceful halt state: #{@target_state}") count = 0 diff --git a/lib/vagrant/action/builtin/nfs.rb b/lib/vagrant/action/builtin/nfs.rb index 364233668..05ec94bc1 100644 --- a/lib/vagrant/action/builtin/nfs.rb +++ b/lib/vagrant/action/builtin/nfs.rb @@ -78,7 +78,8 @@ module Vagrant end # Mount them! - env[:machine].guest.mount_nfs(env[:nfs_host_ip], mount_folders) + env[:machine].guest.capability( + :mount_nfs, env[:nfs_host_ip], mount_folders) end end diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb index 4c7c151ea..d37695f31 100644 --- a/lib/vagrant/errors.rb +++ b/lib/vagrant/errors.rb @@ -243,6 +243,10 @@ module Vagrant error_key(:linux_mount_failed) end + class LinuxNFSMountFailed < VagrantError + error_key(:linux_nfs_mount_failed) + end + class LinuxShellExpandFailed < VagrantError error_key(:linux_shell_expand_failed) end diff --git a/plugins/guests/linux/cap/halt.rb b/plugins/guests/linux/cap/halt.rb new file mode 100644 index 000000000..6125a2082 --- /dev/null +++ b/plugins/guests/linux/cap/halt.rb @@ -0,0 +1,16 @@ +module VagrantPlugins + module GuestLinux + module Cap + class Halt + def self.halt(machine) + begin + machine.communicate.sudo("shutdown -h now") + rescue IOError + # Do nothing, because it probably means the machine shut down + # and SSH connection was lost. + end + end + end + end + end +end diff --git a/plugins/guests/linux/cap/mount_nfs.rb b/plugins/guests/linux/cap/mount_nfs.rb new file mode 100644 index 000000000..efff4fea3 --- /dev/null +++ b/plugins/guests/linux/cap/mount_nfs.rb @@ -0,0 +1,26 @@ +module VagrantPlugins + module GuestLinux + module Cap + class MountNFS + def self.mount_nfs(machine, ip, folders) + folders.each do |name, opts| + # Expand the guest path so we can handle things like "~/vagrant" + expanded_guest_path = machine.guest.capability( + :shell_expand_guest_path, opts[:guestpath]) + + # Do the actual creating and mounting + machine.communicate.sudo("mkdir -p #{expanded_guest_path}") + + # Mount + mount_command = "mount -o vers=#{opts[:nfs_version]} #{ip}:'#{opts[:hostpath]}' #{expanded_guest_path}" + + retryable(:on => Vagrant::Errors::LinuxNFSMountFailed, :tries => 5, :sleep => 2) do + machine.communicate.sudo(mount_command, + :error_class => Vagrant::Errors::LinuxNFSMountFailed) + end + end + end + end + end + end +end diff --git a/plugins/guests/linux/guest.rb b/plugins/guests/linux/guest.rb index 0a9261277..59d09a608 100644 --- a/plugins/guests/linux/guest.rb +++ b/plugins/guests/linux/guest.rb @@ -1,71 +1,12 @@ -require 'log4r' - require "vagrant" -require "vagrant/util/retryable" module VagrantPlugins module GuestLinux class Guest < Vagrant.plugin("2", :guest) - include Vagrant::Util::Retryable - def detect?(machine) # TODO: Linux detection false end - - def halt - begin - @vm.communicate.sudo("shutdown -h now") - rescue IOError - # Do nothing, because it probably means the machine shut down - # and SSH connection was lost. - end - end - - def mount_nfs(ip, folders) - # TODO: Maybe check for nfs support on the guest, since its often - # not installed by default - folders.each do |name, opts| - # Expand the guestpath, so we can handle things like "~/vagrant" - real_guestpath = expanded_guest_path(opts[:guestpath]) - - # Do the actual creating and mounting - @vm.communicate.sudo("mkdir -p #{real_guestpath}") - - retryable(:on => LinuxError, :tries => 5, :sleep => 2) do - @vm.communicate.sudo("mount -o vers=#{opts[:nfs_version]} #{ip}:'#{opts[:hostpath]}' #{real_guestpath}", - :error_class => LinuxError, - :error_key => :mount_nfs_fail) - end - end - end - - protected - - # Determine the real guest path. Since we use a `sudo` shell everywhere - # else, things like '~' don't expand properly in shared folders. We have - # to `echo` here to get that path. - # - # @param [String] guestpath The unexpanded guest path. - # @return [String] The expanded guestpath - def expanded_guest_path(guestpath) - real_guestpath = nil - @vm.communicate.execute("printf #{guestpath}") do |type, data| - if type == :stdout - real_guestpath ||= "" - real_guestpath += data - end - end - - if !real_guestpath - # Really strange error case if this happens. Let's throw an error, - # tell the user to check the echo output. - raise LinuxError, :_key => :guestpath_expand_fail - end - - # Chomp the string so that any trailing newlines are killed - return real_guestpath.chomp - end end end end diff --git a/plugins/guests/linux/plugin.rb b/plugins/guests/linux/plugin.rb index ee0ce1065..91f579048 100644 --- a/plugins/guests/linux/plugin.rb +++ b/plugins/guests/linux/plugin.rb @@ -16,11 +16,21 @@ module VagrantPlugins Guest end + guest_capability("linux", "halt") do + require_relative "cap/halt" + Cap::Halt + end + guest_capability("linux", "shell_expand_guest_path") do require_relative "cap/shell_expand_guest_path" Cap::ShellExpandGuestPath end + guest_capability("linux", "mount_nfs_folder") do + require_relative "cap/mount_nfs" + Cap::MountNFS + end + guest_capability("linux", "mount_virtualbox_shared_folder") do require_relative "cap/mount_virtualbox_shared_folder" Cap::MountVirtualBoxSharedFolder diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 44fd0e801..92768e584 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -211,6 +211,12 @@ en: can work properly. The command attempted was: %{command} + linux_nfs_mount_failed: |- + Mounting NFS shared folders failed. This is most often caused by the NFS + client software not being installed on the guest machine. Please verify + that the NFS client software is properly installed, and consult any resources + specific to the linux distro you're using for more information on how to + do this. linux_shell_expand_failed: |- Vagrant failed to determine the shell expansion of the guest path for one of your shared folders. This is an extremely rare error case @@ -1032,12 +1038,3 @@ en: no_path_or_inline: "One of `path` or `inline` must be set." path_invalid: "`path` for shell provisioner does not exist on the host system: %{path}" upload_path_not_set: "`upload_path` must be set for the shell provisioner." - - guest: - linux: - mount_nfs_fail: |- - Mounting NFS shared folders failed. This is most often caused by the NFS - client software not being installed on the guest machine. Please verify - that the NFS client software is properly installed, and consult any resources - specific to the linux distro you're using for more information on how to - do this. From 067f431ee9f2afefd253cd628ac385b034a005c7 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 23:46:39 -0700 Subject: [PATCH 13/24] Better debugging on searching for capabilities --- lib/vagrant/action/builtin/nfs.rb | 2 +- lib/vagrant/guest.rb | 8 +++++++- plugins/guests/linux/cap/mount_nfs.rb | 6 +++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/vagrant/action/builtin/nfs.rb b/lib/vagrant/action/builtin/nfs.rb index 05ec94bc1..17db963b2 100644 --- a/lib/vagrant/action/builtin/nfs.rb +++ b/lib/vagrant/action/builtin/nfs.rb @@ -79,7 +79,7 @@ module Vagrant # Mount them! env[:machine].guest.capability( - :mount_nfs, env[:nfs_host_ip], mount_folders) + :mount_nfs_folder, env[:nfs_host_ip], mount_folders) end end diff --git a/lib/vagrant/guest.rb b/lib/vagrant/guest.rb index 5629af70f..bc427df0b 100644 --- a/lib/vagrant/guest.rb +++ b/lib/vagrant/guest.rb @@ -146,9 +146,15 @@ module Vagrant # @param [Symbol] cap_name # @return [Module] def capability_module(cap_name) + @logger.debug("Searching for cap: #{cap_name}") @chain.each do |guest_name, guest| + @logger.debug("Checking in: #{guest_name}") caps = @capabilities[guest_name] - return caps[cap_name] if caps && caps.has_key?(cap_name) + + if caps && caps.has_key?(cap_name) + @logger.debug("Found cap: #{cap_name} in #{guest_name}") + return caps[cap_name] + end end nil diff --git a/plugins/guests/linux/cap/mount_nfs.rb b/plugins/guests/linux/cap/mount_nfs.rb index efff4fea3..69d4e92f2 100644 --- a/plugins/guests/linux/cap/mount_nfs.rb +++ b/plugins/guests/linux/cap/mount_nfs.rb @@ -1,8 +1,12 @@ +require "vagrant/util/retryable" + module VagrantPlugins module GuestLinux module Cap class MountNFS - def self.mount_nfs(machine, ip, folders) + extend Vagrant::Util::Retryable + + def self.mount_nfs_folder(machine, ip, folders) folders.each do |name, opts| # Expand the guest path so we can handle things like "~/vagrant" expanded_guest_path = machine.guest.capability( From d490c840df8d2c57440505955d1828d800a62c8b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 23:48:44 -0700 Subject: [PATCH 14/24] Tests passing for halt capability change --- test/unit/vagrant/action/builtin/graceful_halt_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/vagrant/action/builtin/graceful_halt_test.rb b/test/unit/vagrant/action/builtin/graceful_halt_test.rb index 244bf2d17..95bf76888 100644 --- a/test/unit/vagrant/action/builtin/graceful_halt_test.rb +++ b/test/unit/vagrant/action/builtin/graceful_halt_test.rb @@ -34,7 +34,7 @@ describe Vagrant::Action::Builtin::GracefulHalt do it "should do nothing if force is specified" do env[:force_halt] = true - machine_guest.should_not_receive(:halt) + machine_guest.should_not_receive(:capability) described_class.new(app, env, target_state).call(env) @@ -43,7 +43,7 @@ describe Vagrant::Action::Builtin::GracefulHalt do it "should do nothing if there is an invalid source state" do machine_state.stub(:id).and_return(:invalid_source) - machine_guest.should_not_receive(:halt) + machine_guest.should_not_receive(:capability) described_class.new(app, env, target_state, :target_source).call(env) @@ -51,7 +51,7 @@ describe Vagrant::Action::Builtin::GracefulHalt do end it "should gracefully halt and wait for the target state" do - machine_guest.should_receive(:halt).once + machine_guest.should_receive(:capability).with(:halt).once machine_state.stub(:id).and_return(target_state) described_class.new(app, env, target_state).call(env) From 22f3ea66062c7b219881863502fd41ad868444f9 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 23:50:12 -0700 Subject: [PATCH 15/24] Remove the linux config, not used anyways --- plugins/guests/linux/config.rb | 13 ------------- plugins/guests/linux/plugin.rb | 5 ----- 2 files changed, 18 deletions(-) delete mode 100644 plugins/guests/linux/config.rb diff --git a/plugins/guests/linux/config.rb b/plugins/guests/linux/config.rb deleted file mode 100644 index f04b9d42d..000000000 --- a/plugins/guests/linux/config.rb +++ /dev/null @@ -1,13 +0,0 @@ -module VagrantPlugins - module GuestLinux - class Config < Vagrant.plugin("2", :config) - attr_accessor :halt_timeout - attr_accessor :halt_check_interval - - def initialize - @halt_timeout = 30 - @halt_check_interval = 1 - end - end - end -end diff --git a/plugins/guests/linux/plugin.rb b/plugins/guests/linux/plugin.rb index 91f579048..f9531bfa9 100644 --- a/plugins/guests/linux/plugin.rb +++ b/plugins/guests/linux/plugin.rb @@ -6,11 +6,6 @@ module VagrantPlugins name "Linux guest." description "Linux guest support." - config("linux") do - require File.expand_path("../config", __FILE__) - Config - end - guest("linux") do require File.expand_path("../guest", __FILE__) Guest From 0fbe9b0acaae905b36f0ee54b659bb6252f0372c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 3 Apr 2013 23:53:17 -0700 Subject: [PATCH 16/24] Ubuntu change_host_name cap --- plugins/guests/ubuntu/cap/change_host_name.rb | 23 +++++++++++++++++++ plugins/guests/ubuntu/guest.rb | 16 ------------- plugins/guests/ubuntu/plugin.rb | 5 ++++ 3 files changed, 28 insertions(+), 16 deletions(-) create mode 100644 plugins/guests/ubuntu/cap/change_host_name.rb diff --git a/plugins/guests/ubuntu/cap/change_host_name.rb b/plugins/guests/ubuntu/cap/change_host_name.rb new file mode 100644 index 000000000..db052e40f --- /dev/null +++ b/plugins/guests/ubuntu/cap/change_host_name.rb @@ -0,0 +1,23 @@ +module VagrantPlugins + module GuestUbuntu + module Cap + class ChangeHostName + def self.change_host_name(machine, name) + machine.communicate.tap do |comm| + if !comm.test("sudo hostname | grep '^#{name}$'") + comm.sudo("sed -i 's/.*$/#{name}/' /etc/hostname") + comm.sudo("sed -i 's@^\\(127[.]0[.]1[.]1[[:space:]]\\+\\)@\\1#{name} #{name.split('.')[0]} @' /etc/hosts") + if comm.test("[ `lsb_release -c -s` = hardy ]") + # hostname.sh returns 1, so I grep for the right name in /etc/hostname just to have a 0 exitcode + comm.sudo("/etc/init.d/hostname.sh start; grep '#{name}' /etc/hostname") + else + comm.sudo("service hostname start") + end + comm.sudo("hostname --fqdn > /etc/mailname") + end + end + end + end + end + end +end diff --git a/plugins/guests/ubuntu/guest.rb b/plugins/guests/ubuntu/guest.rb index 707f2e8fa..35e3d30c9 100644 --- a/plugins/guests/ubuntu/guest.rb +++ b/plugins/guests/ubuntu/guest.rb @@ -27,22 +27,6 @@ module VagrantPlugins vm.communicate.sudo("[ -x /sbin/initctl ] && /sbin/initctl emit vagrant-mounted MOUNTPOINT=#{real_guestpath}") end end - - def change_host_name(name) - vm.communicate.tap do |comm| - if !comm.test("sudo hostname | grep '^#{name}$'") - comm.sudo("sed -i 's/.*$/#{name}/' /etc/hostname") - comm.sudo("sed -i 's@^\\(127[.]0[.]1[.]1[[:space:]]\\+\\)@\\1#{name} #{name.split('.')[0]} @' /etc/hosts") - if comm.test("[ `lsb_release -c -s` = hardy ]") - # hostname.sh returns 1, so I grep for the right name in /etc/hostname just to have a 0 exitcode - comm.sudo("/etc/init.d/hostname.sh start; grep '#{name}' /etc/hostname") - else - comm.sudo("service hostname start") - end - comm.sudo("hostname --fqdn > /etc/mailname") - end - end - end end end end diff --git a/plugins/guests/ubuntu/plugin.rb b/plugins/guests/ubuntu/plugin.rb index f8e5c0708..38e054972 100644 --- a/plugins/guests/ubuntu/plugin.rb +++ b/plugins/guests/ubuntu/plugin.rb @@ -10,6 +10,11 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("ubuntu", "change_host_name") do + require_relative "cap/change_host_name" + Cap::ChangeHostName + end end end end From 7f33081387d1cfe726414b926c6c204e67f0e08d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 4 Apr 2013 11:39:58 -0700 Subject: [PATCH 17/24] Convert arch to capabilities --- plugins/guests/arch/cap/change_host_name.rb | 18 ++++++++++ plugins/guests/arch/cap/configure_networks.rb | 23 ++++++++++++ plugins/guests/arch/guest.rb | 36 +------------------ plugins/guests/arch/plugin.rb | 10 ++++++ 4 files changed, 52 insertions(+), 35 deletions(-) create mode 100644 plugins/guests/arch/cap/change_host_name.rb create mode 100644 plugins/guests/arch/cap/configure_networks.rb diff --git a/plugins/guests/arch/cap/change_host_name.rb b/plugins/guests/arch/cap/change_host_name.rb new file mode 100644 index 000000000..a32da048e --- /dev/null +++ b/plugins/guests/arch/cap/change_host_name.rb @@ -0,0 +1,18 @@ +module VagrantPlugins + module GuestArch + module Cap + class ChangeHostName + def self.change_host_name(machine, name) + machine.communicate.tap do |comm| + # Only do this if the hostname is not already set + if !comm.test("sudo hostname | grep '#{name}'") + comm.sudo("sed -i 's/\\(HOSTNAME=\\).*/\\1#{name}/' /etc/rc.conf") + comm.sudo("hostname #{name}") + comm.sudo("sed -i 's@^\\(127[.]0[.]0[.]1[[:space:]]\\+\\)@\\1#{name} @' /etc/hosts") + end + end + end + end + end + end +end diff --git a/plugins/guests/arch/cap/configure_networks.rb b/plugins/guests/arch/cap/configure_networks.rb new file mode 100644 index 000000000..11fda5ded --- /dev/null +++ b/plugins/guests/arch/cap/configure_networks.rb @@ -0,0 +1,23 @@ +module VagrantPlugins + module GuestArch + module Cap + class ConfigureNetworks + def self.configure_networks(machine, networks) + networks.each do |network| + entry = TemplateRenderer.render("guests/arch/network_#{network[:type]}", + :options => network) + + temp = Tempfile.new("vagrant") + temp.binmode + temp.write(entry) + temp.close + + machine.communicate.upload(temp.path, "/tmp/vagrant_network") + machine.communicate.sudo("mv /tmp/vagrant_network /etc/network.d/interfaces/eth#{network[:interface]}") + machine.communicate.sudo("netcfg interfaces/eth#{network[:interface]}") + end + end + end + end + end +end diff --git a/plugins/guests/arch/guest.rb b/plugins/guests/arch/guest.rb index a354f6799..116484fd8 100644 --- a/plugins/guests/arch/guest.rb +++ b/plugins/guests/arch/guest.rb @@ -1,45 +1,11 @@ -require 'set' -require 'tempfile' - require "vagrant" -require 'vagrant/util/template_renderer' - -require Vagrant.source_root.join("plugins/guests/linux/guest") module VagrantPlugins module GuestArch - class Guest < VagrantPlugins::GuestLinux::Guest - # Make the TemplateRenderer top-level - include Vagrant::Util - + class Guest < Vagrant.plugin("2", :guest) def detect?(machine) machine.communicate.test("cat /etc/arch-release") end - - def change_host_name(name) - # Only do this if the hostname is not already set - if !vm.communicate.test("sudo hostname | grep '#{name}'") - vm.communicate.sudo("sed -i 's/\\(HOSTNAME=\\).*/\\1#{name}/' /etc/rc.conf") - vm.communicate.sudo("hostname #{name}") - vm.communicate.sudo("sed -i 's@^\\(127[.]0[.]0[.]1[[:space:]]\\+\\)@\\1#{name} @' /etc/hosts") - end - end - - def configure_networks(networks) - networks.each do |network| - entry = TemplateRenderer.render("guests/arch/network_#{network[:type]}", - :options => network) - - temp = Tempfile.new("vagrant") - temp.binmode - temp.write(entry) - temp.close - - vm.communicate.upload(temp.path, "/tmp/vagrant_network") - vm.communicate.sudo("mv /tmp/vagrant_network /etc/network.d/interfaces/eth#{network[:interface]}") - vm.communicate.sudo("netcfg interfaces/eth#{network[:interface]}") - end - end end end end diff --git a/plugins/guests/arch/plugin.rb b/plugins/guests/arch/plugin.rb index 36c2d76ce..ab3a0b016 100644 --- a/plugins/guests/arch/plugin.rb +++ b/plugins/guests/arch/plugin.rb @@ -10,6 +10,16 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("arch", "change_host_name") do + require_relative "cap/change_host_name" + Cap::ChangeHostName + end + + guest_capability("arch", "configure_networks") do + require_relative "cap/configure_networks" + Cap::ConfigureNetworks + end end end end From 0e4e347308c7fa4be94392f1cee0def1092045dd Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 4 Apr 2013 11:49:26 -0700 Subject: [PATCH 18/24] Fedora capabilities --- plugins/guests/fedora/cap/change_host_name.rb | 18 +++++ .../guests/fedora/cap/configure_networks.rb | 54 +++++++++++++++ .../guests/fedora/cap/network_scripts_dir.rb | 15 +++++ plugins/guests/fedora/guest.rb | 66 +------------------ plugins/guests/fedora/plugin.rb | 15 +++++ 5 files changed, 103 insertions(+), 65 deletions(-) create mode 100644 plugins/guests/fedora/cap/change_host_name.rb create mode 100644 plugins/guests/fedora/cap/configure_networks.rb create mode 100644 plugins/guests/fedora/cap/network_scripts_dir.rb diff --git a/plugins/guests/fedora/cap/change_host_name.rb b/plugins/guests/fedora/cap/change_host_name.rb new file mode 100644 index 000000000..6655898d0 --- /dev/null +++ b/plugins/guests/fedora/cap/change_host_name.rb @@ -0,0 +1,18 @@ +module VagrantPlugins + module GuestFedora + module Cap + class ChangeHostName + def self.change_host_name(machine, name) + machine.communicate.tap do |comm| + # Only do this if the hostname is not already set + if !comm.test("sudo hostname | grep '#{name}'") + comm.sudo("sed -i 's/\\(HOSTNAME=\\).*/\\1#{name}/' /etc/sysconfig/network") + comm.sudo("hostname #{name}") + comm.sudo("sed -i 's@^\\(127[.]0[.]0[.]1[[:space:]]\\+\\)@\\1#{name} #{name.split('.')[0]} @' /etc/hosts") + end + end + end + end + end + end +end diff --git a/plugins/guests/fedora/cap/configure_networks.rb b/plugins/guests/fedora/cap/configure_networks.rb new file mode 100644 index 000000000..546d5c516 --- /dev/null +++ b/plugins/guests/fedora/cap/configure_networks.rb @@ -0,0 +1,54 @@ +require "set" +require "tempfile" + +require "vagrant/util/template_renderer" + +module VagrantPlugins + module GuestFedora + module Cap + class ConfigureNetworks + include Vagrant::Util + + def self.configure_networks(machine, networks) + network_scripts_dir = machine.guest.capability("network_scripts_dir") + + # Accumulate the configurations to add to the interfaces file as well + # as what interfaces we're actually configuring since we use that later. + interfaces = Set.new + networks.each do |network| + interfaces.add(network[:interface]) + + # Remove any previous vagrant configuration in this network + # interface's configuration files. + vm.communicate.sudo("touch #{network_scripts_dir}/ifcfg-p7p#{network[:interface]}") + vm.communicate.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' #{network_scripts_dir}/ifcfg-p7p#{network[:interface]} > /tmp/vagrant-ifcfg-p7p#{network[:interface]}") + vm.communicate.sudo("cat /tmp/vagrant-ifcfg-p7p#{network[:interface]} > #{network_scripts_dir}/ifcfg-p7p#{network[:interface]}") + vm.communicate.sudo("rm /tmp/vagrant-ifcfg-p7p#{network[:interface]}") + + # Render and upload the network entry file to a deterministic + # temporary location. + entry = TemplateRenderer.render("guests/fedora/network_#{network[:type]}", + :options => network) + + temp = Tempfile.new("vagrant") + temp.binmode + temp.write(entry) + temp.close + + vm.communicate.upload(temp.path, "/tmp/vagrant-network-entry_#{network[:interface]}") + end + + # Bring down all the interfaces we're reconfiguring. By bringing down + # each specifically, we avoid reconfiguring p7p (the NAT interface) so + # SSH never dies. + interfaces.each do |interface| + vm.communicate.sudo("/sbin/ifdown p7p#{interface} 2> /dev/null", :error_check => false) + vm.communicate.sudo("cat /tmp/vagrant-network-entry_#{interface} >> #{network_scripts_dir}/ifcfg-p7p#{interface}") + vm.communicate.sudo("rm /tmp/vagrant-network-entry_#{interface}") + vm.communicate.sudo("/sbin/ifup p7p#{interface} 2> /dev/null") + end + end + end + end + end +end diff --git a/plugins/guests/fedora/cap/network_scripts_dir.rb b/plugins/guests/fedora/cap/network_scripts_dir.rb new file mode 100644 index 000000000..3ce0e43c3 --- /dev/null +++ b/plugins/guests/fedora/cap/network_scripts_dir.rb @@ -0,0 +1,15 @@ +module VagrantPlugins + module GuestFedora + module Cap + class NetworkScriptsDir + # The path to the directory with the network configuration scripts. + # This is pulled out into its own directory since there are other + # operating systems (SuSE) which behave similarly but with a different + # path to the network scripts. + def self.network_scripts_dir(machine) + "/etc/sysconfig/network-scripts" + end + end + end + end +end diff --git a/plugins/guests/fedora/guest.rb b/plugins/guests/fedora/guest.rb index f32d8f3d2..1127dd28e 100644 --- a/plugins/guests/fedora/guest.rb +++ b/plugins/guests/fedora/guest.rb @@ -1,75 +1,11 @@ -require 'set' -require 'tempfile' - require "vagrant" -require 'vagrant/util/template_renderer' - -require Vagrant.source_root.join("plugins/guests/linux/guest") module VagrantPlugins module GuestFedora - class Guest < VagrantPlugins::GuestLinux::Guest - # Make the TemplateRenderer top-level - include Vagrant::Util - + class Guest < Vagrant.plugin("2", :guest) def detect?(machine) machine.communicate.test("grep 'Fedora release 1[678]' /etc/redhat-release") end - - def configure_networks(networks) - # Accumulate the configurations to add to the interfaces file as well - # as what interfaces we're actually configuring since we use that later. - interfaces = Set.new - networks.each do |network| - interfaces.add(network[:interface]) - - # Remove any previous vagrant configuration in this network - # interface's configuration files. - vm.communicate.sudo("touch #{network_scripts_dir}/ifcfg-p7p#{network[:interface]}") - vm.communicate.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' #{network_scripts_dir}/ifcfg-p7p#{network[:interface]} > /tmp/vagrant-ifcfg-p7p#{network[:interface]}") - vm.communicate.sudo("cat /tmp/vagrant-ifcfg-p7p#{network[:interface]} > #{network_scripts_dir}/ifcfg-p7p#{network[:interface]}") - vm.communicate.sudo("rm /tmp/vagrant-ifcfg-p7p#{network[:interface]}") - - # Render and upload the network entry file to a deterministic - # temporary location. - entry = TemplateRenderer.render("guests/fedora/network_#{network[:type]}", - :options => network) - - temp = Tempfile.new("vagrant") - temp.binmode - temp.write(entry) - temp.close - - vm.communicate.upload(temp.path, "/tmp/vagrant-network-entry_#{network[:interface]}") - end - - # Bring down all the interfaces we're reconfiguring. By bringing down - # each specifically, we avoid reconfiguring p7p (the NAT interface) so - # SSH never dies. - interfaces.each do |interface| - vm.communicate.sudo("/sbin/ifdown p7p#{interface} 2> /dev/null", :error_check => false) - vm.communicate.sudo("cat /tmp/vagrant-network-entry_#{interface} >> #{network_scripts_dir}/ifcfg-p7p#{interface}") - vm.communicate.sudo("rm /tmp/vagrant-network-entry_#{interface}") - vm.communicate.sudo("/sbin/ifup p7p#{interface} 2> /dev/null") - end - end - - # The path to the directory with the network configuration scripts. - # This is pulled out into its own directory since there are other - # operating systems (SuSE) which behave similarly but with a different - # path to the network scripts. - def network_scripts_dir - '/etc/sysconfig/network-scripts' - end - - def change_host_name(name) - # Only do this if the hostname is not already set - if !vm.communicate.test("sudo hostname | grep '#{name}'") - vm.communicate.sudo("sed -i 's/\\(HOSTNAME=\\).*/\\1#{name}/' /etc/sysconfig/network") - vm.communicate.sudo("hostname #{name}") - vm.communicate.sudo("sed -i 's@^\\(127[.]0[.]0[.]1[[:space:]]\\+\\)@\\1#{name} #{name.split('.')[0]} @' /etc/hosts") - end - end end end end diff --git a/plugins/guests/fedora/plugin.rb b/plugins/guests/fedora/plugin.rb index 73bbcb911..b002c1963 100644 --- a/plugins/guests/fedora/plugin.rb +++ b/plugins/guests/fedora/plugin.rb @@ -10,6 +10,21 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("fedora", "change_host_name") do + require_relative "cap/change_host_name" + Cap::ChangeHostName + end + + guest_capability("fedora", "configure_networks") do + require_relative "cap/configure_networks" + Cap::ConfigureNetworks + end + + guest_capability("fedora", "network_scripts_dir") do + require_relative "cap/network_scripts_dir" + Cap::NetworkScriptsDir + end end end end From 8bf9fb17b1bf6257a79184e074386b7744d47b48 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 4 Apr 2013 11:50:05 -0700 Subject: [PATCH 19/24] Remove freeBSD config because it isn't used anymore --- plugins/guests/freebsd/config.rb | 13 ------------- plugins/guests/freebsd/plugin.rb | 5 ----- 2 files changed, 18 deletions(-) delete mode 100644 plugins/guests/freebsd/config.rb diff --git a/plugins/guests/freebsd/config.rb b/plugins/guests/freebsd/config.rb deleted file mode 100644 index 8dfa12edc..000000000 --- a/plugins/guests/freebsd/config.rb +++ /dev/null @@ -1,13 +0,0 @@ -module VagrantPlugins - module GuestFreeBSD - class Config < Vagrant.plugin("2", :config) - attr_accessor :halt_timeout - attr_accessor :halt_check_interval - - def initialize - @halt_timeout = 30 - @halt_check_interval = 1 - end - end - end -end diff --git a/plugins/guests/freebsd/plugin.rb b/plugins/guests/freebsd/plugin.rb index a9d50b7fa..e20cff5c6 100644 --- a/plugins/guests/freebsd/plugin.rb +++ b/plugins/guests/freebsd/plugin.rb @@ -6,11 +6,6 @@ module VagrantPlugins name "FreeBSD guest" description "FreeBSD guest support." - config("freebsd") do - require File.expand_path("../config", __FILE__) - Config - end - guest("freebsd") do require File.expand_path("../guest", __FILE__) Guest From 2c362d4d2854aa89b7598f2d6d22582ba9392199 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 4 Apr 2013 11:56:42 -0700 Subject: [PATCH 20/24] FreeBSD capabilities --- .../guests/freebsd/cap/change_host_name.rb | 14 +++++ .../guests/freebsd/cap/configure_networks.rb | 39 ++++++++++++++ plugins/guests/freebsd/cap/halt.rb | 16 ++++++ .../guests/freebsd/cap/mount_nfs_folder.rb | 14 +++++ plugins/guests/freebsd/guest.rb | 54 ------------------- plugins/guests/freebsd/plugin.rb | 20 +++++++ 6 files changed, 103 insertions(+), 54 deletions(-) create mode 100644 plugins/guests/freebsd/cap/change_host_name.rb create mode 100644 plugins/guests/freebsd/cap/configure_networks.rb create mode 100644 plugins/guests/freebsd/cap/halt.rb create mode 100644 plugins/guests/freebsd/cap/mount_nfs_folder.rb diff --git a/plugins/guests/freebsd/cap/change_host_name.rb b/plugins/guests/freebsd/cap/change_host_name.rb new file mode 100644 index 000000000..513a450bd --- /dev/null +++ b/plugins/guests/freebsd/cap/change_host_name.rb @@ -0,0 +1,14 @@ +module VagrantPlugins + module GuestFreeBSD + module Cap + class ChangeHostName + def self.change_host_name(machine, name) + if !machine.communicate.test("hostname -f | grep '^#{name}$' || hostname -s | grep '^#{name}$'") + machine.communicate.sudo("sed -i '' 's/^hostname=.*$/hostname=#{name}/' /etc/rc.conf") + machine.communicate.sudo("hostname #{name}") + end + end + end + end + end +end diff --git a/plugins/guests/freebsd/cap/configure_networks.rb b/plugins/guests/freebsd/cap/configure_networks.rb new file mode 100644 index 000000000..daca21cfa --- /dev/null +++ b/plugins/guests/freebsd/cap/configure_networks.rb @@ -0,0 +1,39 @@ +require "tempfile" + +require "vagrant/util/template_renderer" + +module VagrantPlugins + module GuestFreeBSD + module Cap + class ConfigureNetworks + extend Vagrant::Util + + def self.configure_networks(machine, networks) + # Remove any previous network additions to the configuration file. + machine.communicate.sudo("sed -i '' -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/rc.conf") + + networks.each do |network| + entry = TemplateRenderer.render("guests/freebsd/network_#{network[:type]}", + :options => network) + + # Write the entry to a temporary location + temp = Tempfile.new("vagrant") + temp.binmode + temp.write(entry) + temp.close + + machine.communicate.upload(temp.path, "/tmp/vagrant-network-entry") + machine.communicate.sudo("su -m root -c 'cat /tmp/vagrant-network-entry >> /etc/rc.conf'") + machine.communicate.sudo("rm /tmp/vagrant-network-entry") + + if network[:type].to_sym == :static + machine.communicate.sudo("ifconfig em#{network[:interface]} inet #{network[:ip]} netmask #{network[:netmask]}") + elsif network[:type].to_sym == :dhcp + machine.communicate.sudo("dhclient em#{network[:interface]}") + end + end + end + end + end + end +end diff --git a/plugins/guests/freebsd/cap/halt.rb b/plugins/guests/freebsd/cap/halt.rb new file mode 100644 index 000000000..938add189 --- /dev/null +++ b/plugins/guests/freebsd/cap/halt.rb @@ -0,0 +1,16 @@ +module VagrantPlugins + module GuestFreeBSD + module Cap + class Halt + def self.halt(machine) + begin + machine.communicate.sudo("shutdown -p now") + rescue IOError + # Do nothing because SSH connection closed and it probably + # means the VM just shut down really fast. + end + end + end + end + end +end diff --git a/plugins/guests/freebsd/cap/mount_nfs_folder.rb b/plugins/guests/freebsd/cap/mount_nfs_folder.rb new file mode 100644 index 000000000..bcd675887 --- /dev/null +++ b/plugins/guests/freebsd/cap/mount_nfs_folder.rb @@ -0,0 +1,14 @@ +module VagrantPlugins + module GuestFreeBSD + module Cap + class MountNFSFolder + def self.mount_nfs_folder(machine, ip, folders) + folders.each do |name, opts| + machine.communicate.sudo("mkdir -p #{opts[:guestpath]}") + machine.communicate.sudo("mount '#{ip}:#{opts[:hostpath]}' '#{opts[:guestpath]}'") + end + end + end + end + end +end diff --git a/plugins/guests/freebsd/guest.rb b/plugins/guests/freebsd/guest.rb index c5ff14951..faaff332e 100644 --- a/plugins/guests/freebsd/guest.rb +++ b/plugins/guests/freebsd/guest.rb @@ -6,25 +6,11 @@ module VagrantPlugins # # Contributed by Kenneth Vestergaard class Guest < Vagrant.plugin("2", :guest) - # Here for whenever it may be used. - class FreeBSDError < Vagrant::Errors::VagrantError - error_namespace("vagrant.guest.freebsd") - end - def detect?(machine) # TODO: FreeBSD detection false end - def halt - begin - vm.communicate.sudo("shutdown -p now") - rescue IOError - # Do nothing because SSH connection closed and it probably - # means the VM just shut down really fast. - end - end - # TODO: vboxsf is currently unsupported in FreeBSD, if you are able to # help out with this project, please contact vbox@FreeBSD.org # @@ -35,46 +21,6 @@ module VagrantPlugins # ssh.exec!("sudo mount -t vboxfs v-root #{guestpath}") # ssh.exec!("sudo chown #{vm.config.ssh.username} #{guestpath}") # end - - def mount_nfs(ip, folders) - folders.each do |name, opts| - vm.communicate.sudo("mkdir -p #{opts[:guestpath]}") - vm.communicate.sudo("mount '#{ip}:#{opts[:hostpath]}' '#{opts[:guestpath]}'") - end - end - - def configure_networks(networks) - # Remove any previous network additions to the configuration file. - vm.communicate.sudo("sed -i '' -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/rc.conf") - - networks.each do |network| - entry = TemplateRenderer.render("guests/freebsd/network_#{network[:type]}", - :options => network) - - # Write the entry to a temporary location - temp = Tempfile.new("vagrant") - temp.binmode - temp.write(entry) - temp.close - - vm.communicate.upload(temp.path, "/tmp/vagrant-network-entry") - vm.communicate.sudo("su -m root -c 'cat /tmp/vagrant-network-entry >> /etc/rc.conf'") - vm.communicate.sudo("rm /tmp/vagrant-network-entry") - - if network[:type].to_sym == :static - vm.communicate.sudo("ifconfig em#{network[:interface]} inet #{network[:ip]} netmask #{network[:netmask]}") - elsif network[:type].to_sym == :dhcp - vm.communicate.sudo("dhclient em#{network[:interface]}") - end - end - end - - def change_host_name(name) - if !vm.communicate.test("hostname -f | grep '^#{name}$' || hostname -s | grep '^#{name}$'") - vm.communicate.sudo("sed -i '' 's/^hostname=.*$/hostname=#{name}/' /etc/rc.conf") - vm.communicate.sudo("hostname #{name}") - end - end end end end diff --git a/plugins/guests/freebsd/plugin.rb b/plugins/guests/freebsd/plugin.rb index e20cff5c6..8e147087b 100644 --- a/plugins/guests/freebsd/plugin.rb +++ b/plugins/guests/freebsd/plugin.rb @@ -10,6 +10,26 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("freebsd", "change_host_name") do + require_relative "cap/change_host_name" + Cap::ChangeHostName + end + + guest_capability("freebsd", "configure_networks") do + require_relative "cap/configure_networks" + Cap::ConfigureNetworks + end + + guest_capability("freebsd", "halt") do + require_relative "cap/halt" + Cap::Halt + end + + guest_capability("freebsd", "mount_nfs_folder") do + require_relative "cap/mount_nfs_folder" + Cap::MountNFSFolder + end end end end From 5e09577a766487e2671ed935050b4273575e249e Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 4 Apr 2013 12:09:40 -0700 Subject: [PATCH 21/24] Lots more guest capabilities converted --- .../guests/fedora/cap/configure_networks.rb | 20 +++--- plugins/guests/fedora/plugin.rb | 7 +- plugins/guests/gentoo/cap/change_host_name.rb | 17 +++++ .../guests/gentoo/cap/configure_networks.rb | 43 ++++++++++++ plugins/guests/gentoo/guest.rb | 48 +------------ plugins/guests/gentoo/plugin.rb | 10 +++ plugins/guests/openbsd/cap/halt.rb | 16 +++++ plugins/guests/openbsd/guest.rb | 8 +-- plugins/guests/openbsd/plugin.rb | 5 ++ plugins/guests/pld/cap/network_scripts_dir.rb | 11 +++ plugins/guests/pld/guest.rb | 8 +-- plugins/guests/pld/plugin.rb | 5 ++ .../cap/change_host_name.rb | 2 +- .../guests/redhat/cap/configure_networks.rb | 55 +++++++++++++++ .../guests/redhat/cap/network_scripts_dir.rb | 11 +++ plugins/guests/redhat/guest.rb | 69 +------------------ plugins/guests/redhat/plugin.rb | 15 ++++ 17 files changed, 204 insertions(+), 146 deletions(-) create mode 100644 plugins/guests/gentoo/cap/change_host_name.rb create mode 100644 plugins/guests/gentoo/cap/configure_networks.rb create mode 100644 plugins/guests/openbsd/cap/halt.rb create mode 100644 plugins/guests/pld/cap/network_scripts_dir.rb rename plugins/guests/{fedora => redhat}/cap/change_host_name.rb (96%) create mode 100644 plugins/guests/redhat/cap/configure_networks.rb create mode 100644 plugins/guests/redhat/cap/network_scripts_dir.rb diff --git a/plugins/guests/fedora/cap/configure_networks.rb b/plugins/guests/fedora/cap/configure_networks.rb index 546d5c516..5699d84b0 100644 --- a/plugins/guests/fedora/cap/configure_networks.rb +++ b/plugins/guests/fedora/cap/configure_networks.rb @@ -7,7 +7,7 @@ module VagrantPlugins module GuestFedora module Cap class ConfigureNetworks - include Vagrant::Util + extend Vagrant::Util def self.configure_networks(machine, networks) network_scripts_dir = machine.guest.capability("network_scripts_dir") @@ -20,10 +20,10 @@ module VagrantPlugins # Remove any previous vagrant configuration in this network # interface's configuration files. - vm.communicate.sudo("touch #{network_scripts_dir}/ifcfg-p7p#{network[:interface]}") - vm.communicate.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' #{network_scripts_dir}/ifcfg-p7p#{network[:interface]} > /tmp/vagrant-ifcfg-p7p#{network[:interface]}") - vm.communicate.sudo("cat /tmp/vagrant-ifcfg-p7p#{network[:interface]} > #{network_scripts_dir}/ifcfg-p7p#{network[:interface]}") - vm.communicate.sudo("rm /tmp/vagrant-ifcfg-p7p#{network[:interface]}") + machine.communicate.sudo("touch #{network_scripts_dir}/ifcfg-p7p#{network[:interface]}") + machine.communicate.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' #{network_scripts_dir}/ifcfg-p7p#{network[:interface]} > /tmp/vagrant-ifcfg-p7p#{network[:interface]}") + machine.communicate.sudo("cat /tmp/vagrant-ifcfg-p7p#{network[:interface]} > #{network_scripts_dir}/ifcfg-p7p#{network[:interface]}") + machine.communicate.sudo("rm /tmp/vagrant-ifcfg-p7p#{network[:interface]}") # Render and upload the network entry file to a deterministic # temporary location. @@ -35,17 +35,17 @@ module VagrantPlugins temp.write(entry) temp.close - vm.communicate.upload(temp.path, "/tmp/vagrant-network-entry_#{network[:interface]}") + machine.communicate.upload(temp.path, "/tmp/vagrant-network-entry_#{network[:interface]}") end # Bring down all the interfaces we're reconfiguring. By bringing down # each specifically, we avoid reconfiguring p7p (the NAT interface) so # SSH never dies. interfaces.each do |interface| - vm.communicate.sudo("/sbin/ifdown p7p#{interface} 2> /dev/null", :error_check => false) - vm.communicate.sudo("cat /tmp/vagrant-network-entry_#{interface} >> #{network_scripts_dir}/ifcfg-p7p#{interface}") - vm.communicate.sudo("rm /tmp/vagrant-network-entry_#{interface}") - vm.communicate.sudo("/sbin/ifup p7p#{interface} 2> /dev/null") + machine.communicate.sudo("/sbin/ifdown p7p#{interface} 2> /dev/null", :error_check => false) + machine.communicate.sudo("cat /tmp/vagrant-network-entry_#{interface} >> #{network_scripts_dir}/ifcfg-p7p#{interface}") + machine.communicate.sudo("rm /tmp/vagrant-network-entry_#{interface}") + machine.communicate.sudo("/sbin/ifup p7p#{interface} 2> /dev/null") end end end diff --git a/plugins/guests/fedora/plugin.rb b/plugins/guests/fedora/plugin.rb index b002c1963..fdfdab807 100644 --- a/plugins/guests/fedora/plugin.rb +++ b/plugins/guests/fedora/plugin.rb @@ -6,16 +6,11 @@ module VagrantPlugins name "Fedora guest" description "Fedora guest support." - guest("fedora", "linux") do + guest("fedora", "redhat") do require File.expand_path("../guest", __FILE__) Guest end - guest_capability("fedora", "change_host_name") do - require_relative "cap/change_host_name" - Cap::ChangeHostName - end - guest_capability("fedora", "configure_networks") do require_relative "cap/configure_networks" Cap::ConfigureNetworks diff --git a/plugins/guests/gentoo/cap/change_host_name.rb b/plugins/guests/gentoo/cap/change_host_name.rb new file mode 100644 index 000000000..4c0f50d8f --- /dev/null +++ b/plugins/guests/gentoo/cap/change_host_name.rb @@ -0,0 +1,17 @@ +module VagrantPlugins + module GuestFreeBSD + module Cap + class ChangeHostName + def self.change_host_name(machine, name) + machine.communicate.tap do |comm| + if !comm.test("sudo hostname --fqdn | grep '#{name}'") + comm.sudo("echo 'hostname=#{name.split('.')[0]}' > /etc/conf.d/hostname") + comm.sudo("sed -i 's@^\\(127[.]0[.]0[.]1[[:space:]]\\+\\)@\\1#{name} #{name.split('.')[0]} @' /etc/hosts") + comm.sudo("hostname #{name.split('.')[0]}") + end + end + end + end + end + end +end diff --git a/plugins/guests/gentoo/cap/configure_networks.rb b/plugins/guests/gentoo/cap/configure_networks.rb new file mode 100644 index 000000000..7234f36d0 --- /dev/null +++ b/plugins/guests/gentoo/cap/configure_networks.rb @@ -0,0 +1,43 @@ +require "tempfile" + +require "vagrant/util/template_renderer" + +module VagrantPlugins + module GuestFreeBSD + module Cap + class ChangeHostName + extend Vagrant::Util + + def self.configure_networks(machine, networks) + machine.communicate.tap do |comm| + # Remove any previous host only network additions to the interface file + comm.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/conf.d/net > /tmp/vagrant-network-interfaces") + comm.sudo("cat /tmp/vagrant-network-interfaces > /etc/conf.d/net") + comm.sudo("rm /tmp/vagrant-network-interfaces") + + # Configure each network interface + networks.each do |network| + entry = TemplateRenderer.render("guests/gentoo/network_#{network[:type]}", + :options => network) + + # Upload the entry to a temporary location + temp = Tempfile.new("vagrant") + temp.binmode + temp.write(entry) + temp.close + + comm.upload(temp.path, "/tmp/vagrant-network-entry") + + # Configure the interface + comm.sudo("ln -fs /etc/init.d/net.lo /etc/init.d/net.eth#{network[:interface]}") + comm.sudo("/etc/init.d/net.eth#{network[:interface]} stop 2> /dev/null") + comm.sudo("cat /tmp/vagrant-network-entry >> /etc/conf.d/net") + comm.sudo("rm /tmp/vagrant-network-entry") + comm.sudo("/etc/init.d/net.eth#{network[:interface]} start") + end + end + end + end + end + end +end diff --git a/plugins/guests/gentoo/guest.rb b/plugins/guests/gentoo/guest.rb index 5aaacd573..33af4ae5d 100644 --- a/plugins/guests/gentoo/guest.rb +++ b/plugins/guests/gentoo/guest.rb @@ -1,55 +1,9 @@ -require 'tempfile' - -require "vagrant" -require 'vagrant/util/template_renderer' - -require Vagrant.source_root.join("plugins/guests/linux/guest") - module VagrantPlugins module GuestGentoo - class Guest < VagrantPlugins::GuestLinux::Guest - # Make the TemplateRenderer top-level - include Vagrant::Util - + class Guest < Vagrant.plugin("2", :guest) def detect?(machine) machine.communicate.test("cat /etc/gentoo-release") end - - def configure_networks(networks) - # Remove any previous host only network additions to the interface file - vm.communicate.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/conf.d/net > /tmp/vagrant-network-interfaces") - vm.communicate.sudo("cat /tmp/vagrant-network-interfaces > /etc/conf.d/net") - vm.communicate.sudo("rm /tmp/vagrant-network-interfaces") - - # Configure each network interface - networks.each do |network| - entry = TemplateRenderer.render("guests/gentoo/network_#{network[:type]}", - :options => network) - - # Upload the entry to a temporary location - temp = Tempfile.new("vagrant") - temp.binmode - temp.write(entry) - temp.close - - vm.communicate.upload(temp.path, "/tmp/vagrant-network-entry") - - # Configure the interface - vm.communicate.sudo("ln -fs /etc/init.d/net.lo /etc/init.d/net.eth#{network[:interface]}") - vm.communicate.sudo("/etc/init.d/net.eth#{network[:interface]} stop 2> /dev/null") - vm.communicate.sudo("cat /tmp/vagrant-network-entry >> /etc/conf.d/net") - vm.communicate.sudo("rm /tmp/vagrant-network-entry") - vm.communicate.sudo("/etc/init.d/net.eth#{network[:interface]} start") - end - end - - def change_host_name(name) - if !vm.communicate.test("sudo hostname --fqdn | grep '#{name}'") - vm.communicate.sudo("echo 'hostname=#{name.split('.')[0]}' > /etc/conf.d/hostname") - vm.communicate.sudo("sed -i 's@^\\(127[.]0[.]0[.]1[[:space:]]\\+\\)@\\1#{name} #{name.split('.')[0]} @' /etc/hosts") - vm.communicate.sudo("hostname #{name.split('.')[0]}") - end - end end end end diff --git a/plugins/guests/gentoo/plugin.rb b/plugins/guests/gentoo/plugin.rb index b37b39565..2054f81cd 100644 --- a/plugins/guests/gentoo/plugin.rb +++ b/plugins/guests/gentoo/plugin.rb @@ -10,6 +10,16 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("gentoo", "change_host_name") do + require_relative "cap/change_host_name" + Cap::ChangeHostName + end + + guest_capability("gentoo", "configure_networks") do + require_relative "cap/configure_networks" + Cap::ConfigureNetworks + end end end end diff --git a/plugins/guests/openbsd/cap/halt.rb b/plugins/guests/openbsd/cap/halt.rb new file mode 100644 index 000000000..3b44d9b0c --- /dev/null +++ b/plugins/guests/openbsd/cap/halt.rb @@ -0,0 +1,16 @@ +module VagrantPlugins + module GuestOpenBSD + module Cap + class Halt + def self.halt(machine) + begin + machine.communicate.sudo("shutdown -p -h now") + rescue IOError + # Do nothing, because it probably means the machine shut down + # and SSH connection was lost. + end + end + end + end + end +end diff --git a/plugins/guests/openbsd/guest.rb b/plugins/guests/openbsd/guest.rb index 8a4e6408d..180c85427 100644 --- a/plugins/guests/openbsd/guest.rb +++ b/plugins/guests/openbsd/guest.rb @@ -1,18 +1,12 @@ require "vagrant" -require Vagrant.source_root.join("plugins/guests/linux/guest") - module VagrantPlugins module GuestOpenBSD - class Guest < VagrantPlugins::GuestLinux::Guest + class Guest < Vagrant.plugin("2", :guest) def detect?(machine) # TODO: OpenBSD detection false end - - def halt - vm.communicate.sudo("shutdown -p -h now") - end end end end diff --git a/plugins/guests/openbsd/plugin.rb b/plugins/guests/openbsd/plugin.rb index dd6f38a76..b3e3312a8 100644 --- a/plugins/guests/openbsd/plugin.rb +++ b/plugins/guests/openbsd/plugin.rb @@ -10,6 +10,11 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("openbsd", "halt") do + require_relative "cap/halt" + Cap::Halt + end end end end diff --git a/plugins/guests/pld/cap/network_scripts_dir.rb b/plugins/guests/pld/cap/network_scripts_dir.rb new file mode 100644 index 000000000..3a6fbfb43 --- /dev/null +++ b/plugins/guests/pld/cap/network_scripts_dir.rb @@ -0,0 +1,11 @@ +module VagrantPlugins + module GuestPld + module Cap + class NetworkScriptsDir + def self.network_scripts_dir(machine) + "/etc/sysconfig/interfaces" + end + end + end + end +end diff --git a/plugins/guests/pld/guest.rb b/plugins/guests/pld/guest.rb index a2d7ad881..1d65ce044 100644 --- a/plugins/guests/pld/guest.rb +++ b/plugins/guests/pld/guest.rb @@ -1,17 +1,11 @@ require "vagrant" -require Vagrant.source_root.join("plugins/guests/redhat/guest") - module VagrantPlugins module GuestPld - class Guest < VagrantPlugins::GuestRedHat::Guest + class Guest < Vagrant.plugin("2", :guest) def detect?(machine) machine.communicate.test("cat /etc/pld-release") end - - def network_scripts_dir - '/etc/sysconfig/interfaces/' - end end end end diff --git a/plugins/guests/pld/plugin.rb b/plugins/guests/pld/plugin.rb index bd457b8c1..d02d76a02 100644 --- a/plugins/guests/pld/plugin.rb +++ b/plugins/guests/pld/plugin.rb @@ -10,6 +10,11 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("pld", "network_scripts_dir") do + require_relative "cap/network_scripts_dir" + Cap::NetworkScriptsDir + end end end end diff --git a/plugins/guests/fedora/cap/change_host_name.rb b/plugins/guests/redhat/cap/change_host_name.rb similarity index 96% rename from plugins/guests/fedora/cap/change_host_name.rb rename to plugins/guests/redhat/cap/change_host_name.rb index 6655898d0..42d1d7d9c 100644 --- a/plugins/guests/fedora/cap/change_host_name.rb +++ b/plugins/guests/redhat/cap/change_host_name.rb @@ -1,5 +1,5 @@ module VagrantPlugins - module GuestFedora + module GuestRedHat module Cap class ChangeHostName def self.change_host_name(machine, name) diff --git a/plugins/guests/redhat/cap/configure_networks.rb b/plugins/guests/redhat/cap/configure_networks.rb new file mode 100644 index 000000000..00ab47766 --- /dev/null +++ b/plugins/guests/redhat/cap/configure_networks.rb @@ -0,0 +1,55 @@ +require "set" +require "tempfile" + +require "vagrant/util/template_renderer" + +module VagrantPlugins + module GuestRedHat + module Cap + class ConfigureNetworks + extend Vagrant::Util + + def self.configure_networks(machine, networks) + network_scripts_dir = machine.guest.capability("network_scripts_dir") + + # Accumulate the configurations to add to the interfaces file as + # well as what interfaces we're actually configuring since we use that + # later. + interfaces = Set.new + networks.each do |network| + interfaces.add(network[:interface]) + + # Remove any previous vagrant configuration in this network interface's + # configuration files. + machine.communicate.sudo("touch #{network_scripts_dir}/ifcfg-eth#{network[:interface]}") + machine.communicate.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' #{network_scripts_dir}/ifcfg-eth#{network[:interface]} > /tmp/vagrant-ifcfg-eth#{network[:interface]}") + machine.communicate.sudo("cat /tmp/vagrant-ifcfg-eth#{network[:interface]} > #{network_scripts_dir}/ifcfg-eth#{network[:interface]}") + machine.communicate.sudo("rm /tmp/vagrant-ifcfg-eth#{network[:interface]}") + + # Render and upload the network entry file to a deterministic + # temporary location. + entry = TemplateRenderer.render("guests/redhat/network_#{network[:type]}", + :options => network) + + temp = Tempfile.new("vagrant") + temp.binmode + temp.write(entry) + temp.close + + machine.communicate.upload(temp.path, "/tmp/vagrant-network-entry_#{network[:interface]}") + end + + # Bring down all the interfaces we're reconfiguring. By bringing down + # each specifically, we avoid reconfiguring eth0 (the NAT interface) so + # SSH never dies. + interfaces.each do |interface| + machine.communicate.sudo("/sbin/ifdown eth#{interface} 2> /dev/null", :error_check => false) + machine.communicate.sudo("cat /tmp/vagrant-network-entry_#{interface} >> #{network_scripts_dir}/ifcfg-eth#{interface}") + machine.communicate.sudo("rm /tmp/vagrant-network-entry_#{interface}") + machine.communicate.sudo("/sbin/ifup eth#{interface} 2> /dev/null") + end + end + end + end + end +end diff --git a/plugins/guests/redhat/cap/network_scripts_dir.rb b/plugins/guests/redhat/cap/network_scripts_dir.rb new file mode 100644 index 000000000..5b2a26e04 --- /dev/null +++ b/plugins/guests/redhat/cap/network_scripts_dir.rb @@ -0,0 +1,11 @@ +module VagrantPlugins + module GuestRedHat + module Cap + class NetworkScriptsDir + def self.network_scripts_dir(machine) + "/etc/sysconfig/network-scripts" + end + end + end + end +end diff --git a/plugins/guests/redhat/guest.rb b/plugins/guests/redhat/guest.rb index 0ac990ea0..197286200 100644 --- a/plugins/guests/redhat/guest.rb +++ b/plugins/guests/redhat/guest.rb @@ -1,78 +1,11 @@ -require 'set' -require 'tempfile' - require "vagrant" -require 'vagrant/util/template_renderer' - -require Vagrant.source_root.join("plugins/guests/linux/guest") module VagrantPlugins module GuestRedHat - class Guest < VagrantPlugins::GuestLinux::Guest - # Make the TemplateRenderer top-level - include Vagrant::Util - + class Guest < Vagrant.plugin("2", :guest) def detect?(machine) machine.communicate.test("cat /etc/redhat-release") end - - def configure_networks(networks) - # Accumulate the configurations to add to the interfaces file as - # well as what interfaces we're actually configuring since we use that - # later. - interfaces = Set.new - networks.each do |network| - interfaces.add(network[:interface]) - - # Remove any previous vagrant configuration in this network interface's - # configuration files. - vm.communicate.sudo("touch #{network_scripts_dir}/ifcfg-eth#{network[:interface]}") - vm.communicate.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' #{network_scripts_dir}/ifcfg-eth#{network[:interface]} > /tmp/vagrant-ifcfg-eth#{network[:interface]}") - vm.communicate.sudo("cat /tmp/vagrant-ifcfg-eth#{network[:interface]} > #{network_scripts_dir}/ifcfg-eth#{network[:interface]}") - vm.communicate.sudo("rm /tmp/vagrant-ifcfg-eth#{network[:interface]}") - - # Render and upload the network entry file to a deterministic - # temporary location. - entry = TemplateRenderer.render("guests/redhat/network_#{network[:type]}", - :options => network) - - temp = Tempfile.new("vagrant") - temp.binmode - temp.write(entry) - temp.close - - vm.communicate.upload(temp.path, "/tmp/vagrant-network-entry_#{network[:interface]}") - end - - # Bring down all the interfaces we're reconfiguring. By bringing down - # each specifically, we avoid reconfiguring eth0 (the NAT interface) so - # SSH never dies. - interfaces.each do |interface| - vm.communicate.sudo("/sbin/ifdown eth#{interface} 2> /dev/null", :error_check => false) - vm.communicate.sudo("cat /tmp/vagrant-network-entry_#{interface} >> #{network_scripts_dir}/ifcfg-eth#{interface}") - vm.communicate.sudo("rm /tmp/vagrant-network-entry_#{interface}") - vm.communicate.sudo("/sbin/ifup eth#{interface} 2> /dev/null") - end - end - - # The path to the directory with the network configuration scripts. - # This is pulled out into its own directory since there are other - # operating systems (SuSE) which behave similarly but with a different - # path to the network scripts. - def network_scripts_dir - '/etc/sysconfig/network-scripts' - end - - def change_host_name(name) - vm.communicate.tap do |comm| - # Only do this if the hostname is not already set - if !comm.test("sudo hostname | grep '#{name}'") - comm.sudo("sed -i 's/\\(HOSTNAME=\\).*/\\1#{name}/' /etc/sysconfig/network") - comm.sudo("hostname #{name}") - comm.sudo("sed -i 's@^\\(127[.]0[.]0[.]1[[:space:]]\\+\\)@\\1#{name} #{name.split('.')[0]} @' /etc/hosts") - end - end - end end end end diff --git a/plugins/guests/redhat/plugin.rb b/plugins/guests/redhat/plugin.rb index dd80ef78f..60ca17af6 100644 --- a/plugins/guests/redhat/plugin.rb +++ b/plugins/guests/redhat/plugin.rb @@ -10,6 +10,21 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("redhat", "change_host_name") do + require_relative "cap/change_host_name" + Cap::ChangeHostName + end + + guest_capability("redhat", "configure_networks") do + require_relative "cap/configure_networks" + Cap::ConfigureNetworks + end + + guest_capability("redhat", "network_scripts_dir") do + require_relative "cap/network_scripts_dir" + Cap::NetworkScriptsDir + end end end end From 439499fc117e28e4b0fff16a031b63e3b41e66e5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 4 Apr 2013 12:25:10 -0700 Subject: [PATCH 22/24] Solaris capabilities --- .../guests/solaris/cap/change_host_name.rb | 17 +++++ .../guests/solaris/cap/configure_networks.rb | 25 +++++++ plugins/guests/solaris/cap/halt.rb | 21 ++++++ .../cap/mount_virtualbox_shared_folder.rb | 28 ++++++++ plugins/guests/solaris/guest.rb | 68 ------------------- plugins/guests/solaris/plugin.rb | 20 ++++++ plugins/guests/suse/cap/change_host_name.rb | 18 +++++ .../guests/suse/cap/network_scripts_dir.rb | 11 +++ plugins/guests/suse/guest.rb | 19 +----- plugins/guests/suse/plugin.rb | 10 +++ 10 files changed, 151 insertions(+), 86 deletions(-) create mode 100644 plugins/guests/solaris/cap/change_host_name.rb create mode 100644 plugins/guests/solaris/cap/configure_networks.rb create mode 100644 plugins/guests/solaris/cap/halt.rb create mode 100644 plugins/guests/solaris/cap/mount_virtualbox_shared_folder.rb create mode 100644 plugins/guests/suse/cap/change_host_name.rb create mode 100644 plugins/guests/suse/cap/network_scripts_dir.rb diff --git a/plugins/guests/solaris/cap/change_host_name.rb b/plugins/guests/solaris/cap/change_host_name.rb new file mode 100644 index 000000000..f9dd19606 --- /dev/null +++ b/plugins/guests/solaris/cap/change_host_name.rb @@ -0,0 +1,17 @@ +module VagrantPlugins + module GuestSolaris + module Cap + class ChangeHostName + def self.change_host_name(machine, name) + su_cmd = machine.config.solaris.suexec_cmd + + # Only do this if the hostname is not already set + if !machine.communicate.test("#{su_cmd} hostname | grep '#{name}'") + machine.communicate.execute("#{su_cmd} sh -c \"echo '#{name}' > /etc/nodename\"") + machine.communicate.execute("#{su_cmd} uname -S #{name}") + end + end + end + end + end +end diff --git a/plugins/guests/solaris/cap/configure_networks.rb b/plugins/guests/solaris/cap/configure_networks.rb new file mode 100644 index 000000000..cff7940d8 --- /dev/null +++ b/plugins/guests/solaris/cap/configure_networks.rb @@ -0,0 +1,25 @@ +module VagrantPlugins + module GuestSolaris + module Cap + class ConfigureNetworks + def self.configure_networks(machine, networks) + networks.each do |network| + device = "#{machine.config.solaris.device}#{network[:interface]}" + su_cmd = machine.config.solaris.suexec_cmd + ifconfig_cmd = "#{su_cmd} /sbin/ifconfig #{device}" + + machine.communicate.execute("#{ifconfig_cmd} plumb") + + if network[:type].to_sym == :static + machine.communicate.execute("#{ifconfig_cmd} inet #{network[:ip]} netmask #{network[:netmask]}") + machine.communicate.execute("#{ifconfig_cmd} up") + machine.communicate.execute("#{su_cmd} sh -c \"echo '#{network[:ip]}' > /etc/hostname.#{device}\"") + elsif network[:type].to_sym == :dhcp + machine.communicate.execute("#{ifconfig_cmd} dhcp start") + end + end + end + end + end + end +end diff --git a/plugins/guests/solaris/cap/halt.rb b/plugins/guests/solaris/cap/halt.rb new file mode 100644 index 000000000..62959c4b7 --- /dev/null +++ b/plugins/guests/solaris/cap/halt.rb @@ -0,0 +1,21 @@ +module VagrantPlugins + module GuestSolaris + module Cap + class Halt + def self.halt(machine) + # There should be an exception raised if the line + # + # vagrant::::profiles=Primary Administrator + # + # does not exist in /etc/user_attr. TODO + begin + machine.communicate.execute("#{machine.config.solaris.suexec_cmd} /usr/sbin/poweroff") + rescue IOError + # Ignore, this probably means connection closed because it + # shut down. + end + end + end + end + end +end diff --git a/plugins/guests/solaris/cap/mount_virtualbox_shared_folder.rb b/plugins/guests/solaris/cap/mount_virtualbox_shared_folder.rb new file mode 100644 index 000000000..dacbee451 --- /dev/null +++ b/plugins/guests/solaris/cap/mount_virtualbox_shared_folder.rb @@ -0,0 +1,28 @@ +module VagrantPlugins + module GuestSolaris + module Cap + class MountVirtualBoxSharedFolder + def self.mount_virtualbox_shared_folder(machine, name, guestpath, options) + # These are just far easier to use than the full options syntax + owner = options[:owner] + group = options[:group] + + # Create the shared folder + machine.communicate.execute("#{machine.config.solaris.suexec_cmd} mkdir -p #{guestpath}") + + # We have to use this `id` command instead of `/usr/bin/id` since this + # one accepts the "-u" and "-g" flags. + id_cmd = "/usr/xpg4/bin/id" + + # Mount the folder with the proper owner/group + mount_options = "-o uid=`#{id_cmd} -u #{owner}`,gid=`#{id_cmd} -g #{group}`" + mount_options += ",#{options[:extra]}" if options[:extra] + machine.communicate.execute("#{machine.config.solaris.suexec_cmd} /sbin/mount -F vboxfs #{mount_options} #{name} #{guestpath}") + + # chown the folder to the proper owner/group + machine.communicate.execute("#{machine.config.solaris.suexec_cmd} chown `#{id_cmd} -u #{owner}`:`#{id_cmd} -g #{group}` #{guestpath}") + end + end + end + end +end diff --git a/plugins/guests/solaris/guest.rb b/plugins/guests/solaris/guest.rb index a815748d0..06b2ae375 100644 --- a/plugins/guests/solaris/guest.rb +++ b/plugins/guests/solaris/guest.rb @@ -6,77 +6,9 @@ module VagrantPlugins # # Contributed by Blake Irvin class Guest < Vagrant.plugin("2", :guest) - # Here for whenever it may be used. - class SolarisError < Vagrant::Errors::VagrantError - error_namespace("vagrant.guest.solaris") - end - def detect?(machine) machine.communicate.test("grep 'Solaris' /etc/release") end - - def configure_networks(networks) - networks.each do |network| - device = "#{vm.config.solaris.device}#{network[:interface]}" - su_cmd = vm.config.solaris.suexec_cmd - ifconfig_cmd = "#{su_cmd} /sbin/ifconfig #{device}" - - vm.communicate.execute("#{ifconfig_cmd} plumb") - - if network[:type].to_sym == :static - vm.communicate.execute("#{ifconfig_cmd} inet #{network[:ip]} netmask #{network[:netmask]}") - vm.communicate.execute("#{ifconfig_cmd} up") - vm.communicate.execute("#{su_cmd} sh -c \"echo '#{network[:ip]}' > /etc/hostname.#{device}\"") - elsif network[:type].to_sym == :dhcp - vm.communicate.execute("#{ifconfig_cmd} dhcp start") - end - end - end - - def change_host_name(name) - su_cmd = vm.config.solaris.suexec_cmd - - # Only do this if the hostname is not already set - if !vm.communicate.test("#{su_cmd} hostname | grep '#{name}'") - vm.communicate.execute("#{su_cmd} sh -c \"echo '#{name}' > /etc/nodename\"") - vm.communicate.execute("#{su_cmd} uname -S #{name}") - end - end - - # There should be an exception raised if the line - # - # vagrant::::profiles=Primary Administrator - # - # does not exist in /etc/user_attr. TODO - def halt - begin - vm.communicate.execute("#{vm.config.solaris.suexec_cmd} /usr/sbin/poweroff") - rescue IOError - # Ignore, this probably means connection closed because it - # shut down. - end - end - - def mount_shared_folder(name, guestpath, options) - # These are just far easier to use than the full options syntax - owner = options[:owner] - group = options[:group] - - # Create the shared folder - vm.communicate.execute("#{vm.config.solaris.suexec_cmd} mkdir -p #{guestpath}") - - # We have to use this `id` command instead of `/usr/bin/id` since this - # one accepts the "-u" and "-g" flags. - id_cmd = "/usr/xpg4/bin/id" - - # Mount the folder with the proper owner/group - mount_options = "-o uid=`#{id_cmd} -u #{owner}`,gid=`#{id_cmd} -g #{group}`" - mount_options += ",#{options[:extra]}" if options[:extra] - vm.communicate.execute("#{vm.config.solaris.suexec_cmd} /sbin/mount -F vboxfs #{mount_options} #{name} #{guestpath}") - - # chown the folder to the proper owner/group - vm.communicate.execute("#{vm.config.solaris.suexec_cmd} chown `#{id_cmd} -u #{owner}`:`#{id_cmd} -g #{group}` #{guestpath}") - end end end end diff --git a/plugins/guests/solaris/plugin.rb b/plugins/guests/solaris/plugin.rb index 844f441b3..9f1fc80d9 100644 --- a/plugins/guests/solaris/plugin.rb +++ b/plugins/guests/solaris/plugin.rb @@ -15,6 +15,26 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("solaris", "change_host_name") do + require_relative "cap/change_host_name" + Cap::ChangeHostName + end + + guest_capability("solaris", "configure_networks") do + require_relative "cap/configure_networks" + Cap::ConfigureNetworks + end + + guest_capability("solaris", "halt") do + require_relative "cap/halt" + Cap::Halt + end + + guest_capability("solaris", "mount_virtualbox_shared_folder") do + require_relative "cap/mount_virtualbox_shared_folder" + Cap::MountVirtualBoxSharedFolder + end end end end diff --git a/plugins/guests/suse/cap/change_host_name.rb b/plugins/guests/suse/cap/change_host_name.rb new file mode 100644 index 000000000..3616171bf --- /dev/null +++ b/plugins/guests/suse/cap/change_host_name.rb @@ -0,0 +1,18 @@ +module VagrantPlugins + module GuestSuse + module Cap + class ChangeHostName + def self.change_host_name(machine, name) + machine.communicate.tap do |comm| + # Only do this if the hostname is not already set + if !comm.test("sudo hostname | grep '#{name}'") + comm.sudo("sed -i 's/\\(HOSTNAME=\\).*/\\1#{name}/' /etc/sysconfig/network") + comm.sudo("hostname #{name}") + comm.sudo("sed -i 's@^\\(127[.]0[.]0[.]1[[:space:]]\\+\\)@\\1#{name} #{name.split('.')[0]} @' /etc/hosts") + end + end + end + end + end + end +end diff --git a/plugins/guests/suse/cap/network_scripts_dir.rb b/plugins/guests/suse/cap/network_scripts_dir.rb new file mode 100644 index 000000000..d8c34b290 --- /dev/null +++ b/plugins/guests/suse/cap/network_scripts_dir.rb @@ -0,0 +1,11 @@ +module VagrantPlugins + module GuestSuse + module Cap + class NetworkScriptsDir + def self.network_scripts_dir(machine) + "/etc/sysconfig/network/" + end + end + end + end +end diff --git a/plugins/guests/suse/guest.rb b/plugins/guests/suse/guest.rb index e6caeda45..340f5818d 100644 --- a/plugins/guests/suse/guest.rb +++ b/plugins/guests/suse/guest.rb @@ -1,28 +1,11 @@ require "vagrant" -require Vagrant.source_root.join("plugins/guests/redhat/guest") - module VagrantPlugins module GuestSuse - class Guest < VagrantPlugins::GuestRedHat::Guest + class Guest < Vagrant.plugin("2", :guest) def detect?(machine) machine.communicate.test("cat /etc/SuSE-release") end - - def network_scripts_dir - '/etc/sysconfig/network/' - end - - def change_host_name(name) - vm.communicate.tap do |comm| - # Only do this if the hostname is not already set - if !comm.test("sudo hostname | grep '#{name}'") - comm.sudo("echo '#{name}' > /etc/HOSTNAME") - comm.sudo("hostname #{name}") - comm.sudo("sed -i 's@^\\(127[.]0[.]0[.]1[[:space:]]\\+\\)@\\1#{name} #{name.split('.')[0]} @' /etc/hosts") - end - end - end end end end diff --git a/plugins/guests/suse/plugin.rb b/plugins/guests/suse/plugin.rb index 0fd401ea7..bf9fbfbb3 100644 --- a/plugins/guests/suse/plugin.rb +++ b/plugins/guests/suse/plugin.rb @@ -10,6 +10,16 @@ module VagrantPlugins require File.expand_path("../guest", __FILE__) Guest end + + guest_capability("suse", "change_host_name") do + require_relative "cap/change_host_name" + Cap::ChangeHostName + end + + guest_capability("suse", "network_scripts_dir") do + require_relative "cap/network_scripts_dir" + Cap::NetworkScriptsDir + end end end end From 7b9e5fd4a787cd7d0db0fee95ccd54f0992cd64d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 4 Apr 2013 12:25:40 -0700 Subject: [PATCH 23/24] Include should be extend for class methods --- plugins/guests/debian/cap/configure_networks.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/guests/debian/cap/configure_networks.rb b/plugins/guests/debian/cap/configure_networks.rb index 16e50158e..0cb3d006f 100644 --- a/plugins/guests/debian/cap/configure_networks.rb +++ b/plugins/guests/debian/cap/configure_networks.rb @@ -7,7 +7,7 @@ module VagrantPlugins module GuestDebian module Cap class ConfigureNetworks - include Vagrant::Util + extend Vagrant::Util def self.configure_networks(machine, networks) machine.communicate.tap do |comm| From 296d32c0993bd6a24594b5e637cfb0e730029588 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 4 Apr 2013 12:58:07 -0700 Subject: [PATCH 24/24] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 994bc3e78..1fe83eecc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ FEATURES: Note that while this feature is available, the "Vagrant way" is instead to use box manifests to ensure that the "box" for every provider matches, so these sorts of overrides are unnecessary. + - A new "guest capabilities" system to replace the old "guest" system. + This new abstraction allows plugins to define "capabilities" that + certain guest operating systems can implement. This allows greater + flexibility in doing guest-specific behavior. IMPROVEMENTS: