Class: Vagrant::Machine

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

Overview

This represents a machine that Vagrant manages. This provides a singular API for querying the state and making state changes to the machine, which is backed by any sort of provider (VirtualBox, VMWare, etc.).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, provider_name, provider_cls, provider_config, provider_options, config, data_dir, box, env, base = false) ⇒ Machine

Initialize a new machine.

Parameters:

  • name (String)

    Name of the virtual machine.

  • provider (Class)

    The provider backing this machine. This is currently expected to be a V1 ‘provider` plugin.

  • provider_config (Object)

    The provider-specific configuration for this machine.

  • provider_options (Hash)

    The provider-specific options from the plugin definition.

  • config (Object)

    The configuration for this machine.

  • data_dir (Pathname)

    The directory where machine-specific data can be stored. This directory is ensured to exist.

  • box (Box)

    The box that is backing this virtual machine.

  • env (Environment)

    The environment that this machine is a part of.



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
111
112
113
114
115
116
117
# File 'lib/vagrant/machine.rb', line 80

def initialize(name, provider_name, provider_cls, provider_config, provider_options, config, data_dir, box, env, base=false)
  @logger = Log4r::Logger.new("vagrant::machine")
  @logger.info("Initializing machine: #{name}")
  @logger.info("  - Provider: #{provider_cls}")
  @logger.info("  - Box: #{box}")
  @logger.info("  - Data dir: #{data_dir}")

  @box             = box
  @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
  @provider_options = provider_options
  @ui              = @env.ui.scope(@name)

  # Read the ID, which is usually in local storage
  @id = nil

  # XXX: This is temporary. This will be removed very soon.
  if base
    @id = name
  else
    # Read the id file from the data directory if it exists as the
    # ID for the pre-existing physical representation of this machine.
    id_file = @data_dir.join("id")
    @id = id_file.read.chomp if id_file.file?
  end

  # Initializes the provider last so that it has access to all the
  # state we setup on this machine.
  @provider = provider_cls.new(self)
end

Instance Attribute Details

#boxBox (readonly)

The box that is backing this machine.

Returns:



11
12
13
# File 'lib/vagrant/machine.rb', line 11

def box
  @box
end

#configObject (readonly)

Configuration for the machine.

Returns:

  • (Object)


16
17
18
# File 'lib/vagrant/machine.rb', line 16

def config
  @config
end

#data_dirPathname (readonly)

Directory where machine-specific data can be stored.

Returns:

  • (Pathname)


21
22
23
# File 'lib/vagrant/machine.rb', line 21

def data_dir
  @data_dir
end

#envEnvironment (readonly)

The environment that this machine is a part of.

Returns:



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

def env
  @env
end

#idString

ID of the machine. This ID comes from the provider and is not guaranteed to be of any particular format except that it is a string.

Returns:

  • (String)


33
34
35
# File 'lib/vagrant/machine.rb', line 33

def id
  @id
end

#nameString (readonly)

Name of the machine. This is assigned by the Vagrantfile.

Returns:

  • (String)


38
39
40
# File 'lib/vagrant/machine.rb', line 38

def name
  @name
end

#providerObject (readonly)

The provider backing this machine.

Returns:

  • (Object)


43
44
45
# File 'lib/vagrant/machine.rb', line 43

def provider
  @provider
end

#provider_configObject (readonly)

The provider-specific configuration for this machine.

Returns:

  • (Object)


48
49
50
# File 'lib/vagrant/machine.rb', line 48

def provider_config
  @provider_config
end

#provider_nameSymbol (readonly)

The name of the provider.

Returns:

  • (Symbol)


53
54
55
# File 'lib/vagrant/machine.rb', line 53

def provider_name
  @provider_name
end

#provider_optionsHash (readonly)

The options given to the provider when registering the plugin.

Returns:

  • (Hash)


58
59
60
# File 'lib/vagrant/machine.rb', line 58

def provider_options
  @provider_options
end

#uiUI (readonly)

The UI for outputting in the scope of this machine.

Returns:



63
64
65
# File 'lib/vagrant/machine.rb', line 63

def ui
  @ui
end

Instance Method Details

#action(name, extra_env = nil) ⇒ Object

This calls an action on the provider. The provider may or may not actually implement the action.

Parameters:

  • name (Symbol)

    Name of the action to run.

  • extra_env (Hash) (defaults to: nil)

    This data will be passed into the action runner as extra data set on the environment hash for the middleware runner.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/vagrant/machine.rb', line 126

def action(name, extra_env=nil)
  @logger.info("Calling action: #{name} on provider #{@provider}")

  # Get the callable from the provider.
  callable = @provider.action(name)

  # If this action doesn't exist on the provider, then an exception
  # must be raised.
  if callable.nil?
    raise Errors::UnimplementedProviderAction,
      :action => name,
      :provider => @provider.to_s
  end

  # Run the action with the action runner on the environment
  env = {
    :action_name    => "machine_action_#{name}".to_sym,
    :machine        => self,
    :machine_action => name,
    :ui             => @ui
  }.merge(extra_env || {})
  @env.action_runner.run(callable, env)
end

#communicateObject

Returns a communication object for executing commands on the remote machine. Note that the exact semantics of this are up to the communication provider itself. Despite this, the semantics are expected to be consistent across operating systems. For example, all linux-based systems should have similar communication (usually a shell). All Windows systems should have similar communication as well. Therefore, prior to communicating with the machine, users of this method are expected to check the guest OS to determine their behavior.

This method will always return some valid communication object. The ‘ready?` API can be used on the object to check if communication is actually ready.

Returns:

  • (Object)


164
165
166
167
168
169
170
171
172
173
# File 'lib/vagrant/machine.rb', line 164

def communicate
  if !@communicator
    # For now, we always return SSH. In the future, we'll abstract
    # this and allow plugins to define new methods of communication.
    klass = Vagrant.plugin("2").manager.communicators[:ssh]
    @communicator = klass.new(self)
  end

  @communicator
end

#guestGuest

Returns a guest implementation for this machine. The guest implementation knows how to do guest-OS specific tasks, such as configuring networks, mounting folders, etc.

Returns:

Raises:



180
181
182
183
184
# File 'lib/vagrant/machine.rb', line 180

def guest
  raise Errors::MachineGuestNotReady if !communicate.ready?
  @guest.detect! if !@guest.ready?
  @guest
end

#inspectString

This returns a clean inspect value so that printing the value via a pretty print (‘p`) results in a readable value.

Returns:

  • (String)


234
235
236
# File 'lib/vagrant/machine.rb', line 234

def inspect
  "#<#{self.class}: #{@name} (#{@provider.class})>"
end

#ssh_infoHash

This returns the SSH info for accessing this machine. This SSH info is queried from the underlying provider. This method returns ‘nil` if the machine is not ready for SSH communication.

The structure of the resulting hash is guaranteed to contain the following structure, although it may return other keys as well not documented here:

{
  :host => "1.2.3.4",
  :port => "22",
  :username => "mitchellh",
  :private_key_path => "/path/to/my/key"
}

Note that Vagrant makes no guarantee that this info works or is correct. This is simply the data that the provider gives us or that is configured via a Vagrantfile. It is still possible after this point when attempting to connect via SSH to get authentication errors.

Returns:

  • (Hash)

    SSH information.



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/vagrant/machine.rb', line 260

def ssh_info
  # First, ask the provider for their information. If the provider
  # returns nil, then the machine is simply not ready for SSH, and
  # we return nil as well.
  info = @provider.ssh_info
  return nil if info.nil?

  # Delete out the nil entries.
  info.dup.each do |key, value|
    info.delete(key) if value.nil?
  end

  # We set the defaults
  info[:host] ||= @config.ssh.default.host
  info[:port] ||= @config.ssh.default.port
  info[:private_key_path] ||= @config.ssh.default.private_key_path
  info[:username] ||= @config.ssh.default.username

  # We set overrides if they are set. These take precedence over
  # provider-returned data.
  info[:host] = @config.ssh.host if @config.ssh.host
  info[:port] = @config.ssh.port if @config.ssh.port
  info[:username] = @config.ssh.username if @config.ssh.username

  # We also set some fields that are purely controlled by Varant
  info[:forward_agent] = @config.ssh.forward_agent
  info[:forward_x11]   = @config.ssh.forward_x11

  # Add in provided proxy command config
  info[:proxy_command] = @config.ssh.proxy_command if @config.ssh.proxy_command

  # Set the private key path. If a specific private key is given in
  # the Vagrantfile we set that. Otherwise, we use the default (insecure)
  # private key, but only if the provider didn't give us one.
  if !info[:private_key_path]
    if @config.ssh.private_key_path
      info[:private_key_path] = @config.ssh.private_key_path
    else
      info[:private_key_path] = @env.default_private_key_path
    end
  end

  # Expand the private key path relative to the root path
  info[:private_key_path] = File.expand_path(info[:private_key_path], @env.root_path)

  # Return the final compiled SSH info data
  info
end

#stateSymbol

Returns the state of this machine. The state is queried from the backing provider, so it can be any arbitrary symbol.

Returns:

  • (Symbol)

Raises:



313
314
315
316
317
# File 'lib/vagrant/machine.rb', line 313

def state
  result = @provider.state
  raise Errors::MachineStateInvalid if !result.is_a?(MachineState)
  result
end