Class: Vagrant::Guest

Inherits:
Object
  • Object
show all
Defined in:
lib/vagrant/guest.rb

Overview

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.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(machine, guests, capabilities) ⇒ Guest



28
29
30
31
32
33
34
35
# File 'lib/vagrant/guest.rb', line 28

def initialize(machine, guests, capabilities)
  @logger       = Log4r::Logger.new("vagrant::guest")
  @capabilities = capabilities
  @chain        = []
  @guests       = guests
  @machine      = machine
  @name         = nil
end

Instance Attribute Details

#chainObject (readonly)

Returns the value of attribute chain.



20
21
22
# File 'lib/vagrant/guest.rb', line 20

def chain
  @chain
end

#nameSymbol (readonly)

The name of the guest OS. This is available after #detect! is called.



26
27
28
# File 'lib/vagrant/guest.rb', line 26

def name
  @name
end

Instance Method Details

#capability(cap_name, *args) ⇒ Object

Executes the capability with the given name, optionally passing more arguments onwards to the capability.



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/vagrant/guest.rb', line 121

def capability(cap_name, *args)
  @logger.info("Execute capability: #{cap_name} (#{@chain[0][0]})")
  cap_mod = capability_module(cap_name.to_sym)
  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

#capability?(cap_name) ⇒ Boolean

Tests whether the guest has the named capability.



115
116
117
# File 'lib/vagrant/guest.rb', line 115

def capability?(cap_name)
  !capability_module(cap_name.to_sym).nil?
end

#detect!Object

This will detect the proper guest OS for the machine and set up the class to actually execute capabilities.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/vagrant/guest.rb', line 39

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 a specific guest was specified, then attempt to use that
        # guest no matter what. Otherwise, only use it if it was detected.
        use_this_guest = false
        if @machine.config.vm.guest.nil?
          use_this_guest = guest.detect?(@machine)
        else
          use_this_guest = @machine.config.vm.guest.to_sym == name.to_sym
        end

        if use_this_guest
          @logger.info("Detected: #{name}!")
          @chain << [name, guest]
          @name = name

          # Build the proper chain of parents if there are any.
          # This allows us to do "inheritance" 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

#ready?Boolean

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.



147
148
149
# File 'lib/vagrant/guest.rb', line 147

def ready?
  !@chain.empty?
end