Merge branch 'guest-capabilities-system'
This replaces the old "guest" sysetm with a new "guest + capabilities" system. This introduces two new abstractions to replace the old system: 1. Guests - These are responsible for simply detecting the guest OS. 2. Guest Capabilities - These are specific tasks that a guest OS are capable of performing. For example, "mount_virtualbox_shared_folders" or "configure_networks" This new system improves the old system because the old system hardcoded all capabilities of guests into a single static class. This system allows dynamically adding new capabilities as they're needed and testing for their existence. This means it is now possible for the Chef provisioner (as an example) to run the "install_chef" capability if it exists, allowing guests to handle installing Chef. COOL! If the capability doesn't exist, Chef can ignore it, error, etc. Plugins can dynamically add new capabilities to existing operating systems. AWESOME!
This commit is contained in:
commit
fd0661c20e
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_folder, env[:nfs_host_ip], mount_folders)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -227,6 +227,30 @@ 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
|
||||
|
||||
class LinuxMountFailed < VagrantError
|
||||
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
|
||||
|
||||
class LocalDataDirectoryNotAccessible < VagrantError
|
||||
error_key(:local_data_dir_not_accessible)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
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
|
||||
|
||||
# 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
|
||||
# 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 << [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_name = guest_info[1]
|
||||
parent_info = @guests[parent_name]
|
||||
while parent_info
|
||||
@chain << [parent_name, parent_info[0].new]
|
||||
parent_name = parent_info[1]
|
||||
parent_info = @guests[parent_name]
|
||||
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
|
||||
|
||||
# Tests whether the guest has the named capability.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def capability?(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, *args)
|
||||
@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
|
||||
|
||||
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(@machine, *args)
|
||||
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
|
||||
|
||||
protected
|
||||
|
||||
# Returns the registered module for a capability with the given name.
|
||||
#
|
||||
# @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]
|
||||
|
||||
if caps && caps.has_key?(cap_name)
|
||||
@logger.debug("Found cap: #{cap_name} in #{guest_name}")
|
||||
return caps[cap_name]
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -83,6 +83,10 @@ module Vagrant
|
|||
@config = config
|
||||
@data_dir = data_dir
|
||||
@env = env
|
||||
@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
|
||||
|
@ -166,35 +170,11 @@ 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?
|
||||
|
||||
# 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.detect! if !@guest.ready?
|
||||
@guest
|
||||
end
|
||||
|
||||
# This sets the unique ID associated with this machine. This will
|
||||
|
|
|
@ -16,6 +16,16 @@ module Vagrant
|
|||
# @return [Hash<Symbol, Registry>]
|
||||
attr_reader :configs
|
||||
|
||||
# This contains all the guests and their parents.
|
||||
#
|
||||
# @return [Registry<Symbol, Array<Class, Symbol>>]
|
||||
attr_reader :guests
|
||||
|
||||
# This contains all the registered guest capabilities.
|
||||
#
|
||||
# @return [Hash<Symbol, Registry>]
|
||||
attr_reader :guest_capabilities
|
||||
|
||||
# This contains all the provider plugins by name, and returns
|
||||
# the provider class and options.
|
||||
#
|
||||
|
@ -27,6 +37,8 @@ module Vagrant
|
|||
@action_hooks = Hash.new { |h, k| h[k] = [] }
|
||||
|
||||
@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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -67,11 +67,26 @@ 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
|
||||
|
||||
# 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]
|
||||
|
|
|
@ -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,26 @@ 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
|
||||
[block.call, parent]
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
# Return the registry
|
||||
data[:guests]
|
||||
# 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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -1,40 +1,10 @@
|
|||
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
|
||||
|
||||
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
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("cat /etc/arch-release")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,10 +6,20 @@ module VagrantPlugins
|
|||
name "Arch guest"
|
||||
description "Arch guest support."
|
||||
|
||||
guest("arch") do
|
||||
guest("arch", "linux") do
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,61 @@
|
|||
require 'set'
|
||||
require 'tempfile'
|
||||
|
||||
require "vagrant/util/template_renderer"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestDebian
|
||||
module Cap
|
||||
class ConfigureNetworks
|
||||
extend 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
|
|
@ -1,71 +1,8 @@
|
|||
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
|
||||
|
||||
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}$'")
|
||||
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
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("cat /proc/version | grep 'Debian'")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,10 +6,20 @@ module VagrantPlugins
|
|||
name "Debian guest"
|
||||
description "Debian guest support."
|
||||
|
||||
guest("debian") do
|
||||
guest("debian", "linux") do
|
||||
require File.expand_path("../guest", __FILE__)
|
||||
Guest
|
||||
end
|
||||
|
||||
guest_capability("debian", "configure_networks") do
|
||||
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
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
require "set"
|
||||
require "tempfile"
|
||||
|
||||
require "vagrant/util/template_renderer"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestFedora
|
||||
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-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.
|
||||
entry = TemplateRenderer.render("guests/fedora/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 p7p (the NAT interface) so
|
||||
# SSH never dies.
|
||||
interfaces.each do |interface|
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
|
@ -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
|
|
@ -1,70 +1,10 @@
|
|||
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
|
||||
|
||||
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
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("grep 'Fedora release 1[678]' /etc/redhat-release")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,10 +6,20 @@ module VagrantPlugins
|
|||
name "Fedora guest"
|
||||
description "Fedora guest support."
|
||||
|
||||
guest("fedora") do
|
||||
guest("fedora", "redhat") do
|
||||
require File.expand_path("../guest", __FILE__)
|
||||
Guest
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -6,18 +6,9 @@ module VagrantPlugins
|
|||
#
|
||||
# Contributed by Kenneth Vestergaard <kvs@binarysolutions.dk>
|
||||
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 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
|
||||
def detect?(machine)
|
||||
# TODO: FreeBSD detection
|
||||
false
|
||||
end
|
||||
|
||||
# TODO: vboxsf is currently unsupported in FreeBSD, if you are able to
|
||||
|
@ -30,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
|
||||
|
|
|
@ -6,15 +6,30 @@ 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
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -1,50 +1,8 @@
|
|||
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
|
||||
|
||||
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
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("cat /etc/gentoo-release")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,10 +6,20 @@ module VagrantPlugins
|
|||
name "Gentoo guest"
|
||||
description "Gentoo guest support."
|
||||
|
||||
guest("gentoo") do
|
||||
guest("gentoo", "linux") do
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,30 @@
|
|||
require "vagrant/util/retryable"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestLinux
|
||||
module Cap
|
||||
class MountNFS
|
||||
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(
|
||||
: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
|
|
@ -0,0 +1,40 @@
|
|||
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
|
||||
raise Vagrant::Errors::LinuxMountFailed, :command => mount_command
|
||||
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
|
|
@ -0,0 +1,26 @@
|
|||
module VagrantPlugins
|
||||
module GuestLinux
|
||||
module Cap
|
||||
class ShellExpandGuestPath
|
||||
def self.shell_expand_guest_path(machine, path)
|
||||
real_path = nil
|
||||
machine.communicate.execute("printf #{path}") 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.
|
||||
raise LinuxShellExpandFailed
|
||||
end
|
||||
|
||||
# Chomp the string so that any trailing newlines are killed
|
||||
return real_path.chomp
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -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
|
|
@ -1,124 +1,11 @@
|
|||
require 'log4r'
|
||||
|
||||
require "vagrant"
|
||||
require "vagrant/util/retryable"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestLinux
|
||||
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 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")
|
||||
rescue IOError
|
||||
# Do nothing, because it probably means the machine shut down
|
||||
# and SSH connection was lost.
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
def detect?(machine)
|
||||
# TODO: Linux detection
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,15 +6,30 @@ 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
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
|
@ -1,12 +1,11 @@
|
|||
require "vagrant"
|
||||
|
||||
require Vagrant.source_root.join("plugins/guests/linux/guest")
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestOpenBSD
|
||||
class Guest < VagrantPlugins::GuestLinux::Guest
|
||||
def halt
|
||||
vm.communicate.sudo("shutdown -p -h now")
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
# TODO: OpenBSD detection
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,10 +6,15 @@ module VagrantPlugins
|
|||
name "OpenBSD guest"
|
||||
description "OpenBSD guest support."
|
||||
|
||||
guest("openbsd") do
|
||||
guest("openbsd", "linux") do
|
||||
require File.expand_path("../guest", __FILE__)
|
||||
Guest
|
||||
end
|
||||
|
||||
guest_capability("openbsd", "halt") do
|
||||
require_relative "cap/halt"
|
||||
Cap::Halt
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
|
@ -1,12 +1,10 @@
|
|||
require "vagrant"
|
||||
|
||||
require Vagrant.source_root.join("plugins/guests/redhat/guest")
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestPld
|
||||
class Guest < VagrantPlugins::GuestRedHat::Guest
|
||||
def network_scripts_dir
|
||||
'/etc/sysconfig/interfaces/'
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("cat /etc/pld-release")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,10 +6,15 @@ 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
|
||||
|
||||
guest_capability("pld", "network_scripts_dir") do
|
||||
require_relative "cap/network_scripts_dir"
|
||||
Cap::NetworkScriptsDir
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
module VagrantPlugins
|
||||
module GuestRedHat
|
||||
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
|
|
@ -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
|
|
@ -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
|
|
@ -1,73 +1,10 @@
|
|||
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
|
||||
|
||||
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
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("cat /etc/redhat-release")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,10 +6,25 @@ module VagrantPlugins
|
|||
name "RedHat guest"
|
||||
description "RedHat guest support."
|
||||
|
||||
guest("redhat") do
|
||||
guest("redhat", "linux") do
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -6,72 +6,8 @@ module VagrantPlugins
|
|||
#
|
||||
# Contributed by Blake Irvin <b.irvin@modcloth.com>
|
||||
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 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}")
|
||||
def detect?(machine)
|
||||
machine.communicate.test("grep 'Solaris' /etc/release")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -1,23 +1,10 @@
|
|||
require "vagrant"
|
||||
|
||||
require Vagrant.source_root.join("plugins/guests/redhat/guest")
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestSuse
|
||||
class Guest < VagrantPlugins::GuestRedHat::Guest
|
||||
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
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("cat /etc/SuSE-release")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,10 +6,20 @@ module VagrantPlugins
|
|||
name "SUSE guest"
|
||||
description "SUSE guest support."
|
||||
|
||||
guest("suse") do
|
||||
guest("suse", "redhat") do
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
@ -23,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
|
||||
|
|
|
@ -6,10 +6,15 @@ module VagrantPlugins
|
|||
name "Ubuntu guest"
|
||||
description "Ubuntu guest support."
|
||||
|
||||
guest("ubuntu") do
|
||||
guest("ubuntu", "debian") do
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -173,18 +173,23 @@ 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_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
|
||||
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.
|
||||
|
@ -199,6 +204,24 @@ 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_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
|
||||
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
|
||||
|
@ -1015,56 +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:
|
||||
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_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
|
||||
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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
require "pathname"
|
||||
|
||||
require File.expand_path("../../base", __FILE__)
|
||||
|
||||
describe Vagrant::Guest do
|
||||
include_context "unit"
|
||||
|
||||
let(:capabilities) { {} }
|
||||
let(:guests) { {} }
|
||||
let(:machine) do
|
||||
double("machine").tap do |m|
|
||||
m.stub(:inspect => "machine")
|
||||
end
|
||||
end
|
||||
|
||||
subject { described_class.new(machine, guests, capabilities) }
|
||||
|
||||
# This registers a capability with a specific guest
|
||||
def register_capability(guest, capability, options=nil)
|
||||
options ||= {}
|
||||
|
||||
cap = Class.new do
|
||||
if !options[:corrupt]
|
||||
define_method(capability) do |*args|
|
||||
raise "cap: #{capability} #{args.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
capabilities[guest] ||= {}
|
||||
capabilities[guest][capability] = cap.new
|
||||
end
|
||||
|
||||
# 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 "#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 [machine]")
|
||||
end
|
||||
|
||||
it "executes the capability with arguments" do
|
||||
register_capability(:bar, :test)
|
||||
|
||||
expect { subject.capability(:test, 1) }.
|
||||
to raise_error(RuntimeError, "cap: test [machine, 1]")
|
||||
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)
|
||||
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)
|
||||
register_guest(:bar, nil, true)
|
||||
register_guest(:baz, nil, false)
|
||||
|
||||
subject.detect!
|
||||
subject.name.should == :bar
|
||||
subject.chain.length.should == 1
|
||||
subject.chain[0][0].should == :bar
|
||||
subject.chain[0][1].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.name.should == :baz
|
||||
subject.chain.length.should == 3
|
||||
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
|
||||
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
|
|
@ -197,10 +197,21 @@ describe Vagrant::Machine do
|
|||
let(:communicator) do
|
||||
result = double("communicator")
|
||||
result.stub(:ready?).and_return(true)
|
||||
result.stub(:test).and_return(false)
|
||||
result
|
||||
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
|
||||
|
||||
|
@ -212,63 +223,11 @@ describe Vagrant::Machine do
|
|||
end
|
||||
|
||||
it "should return the configured guest" do
|
||||
test_guest = Class.new(Vagrant.plugin("2", :guest))
|
||||
|
||||
register_plugin do |p|
|
||||
p.guest(:test) { test_guest }
|
||||
end
|
||||
|
||||
config.vm.guest = :test
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
|
|
@ -92,15 +92,32 @@ 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 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
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue