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.).
The box that is backing this machine.
@return [Box]
Configuration for the machine.
@return [Object]
Directory where machine-specific data can be stored.
@return [Pathname]
The environment that this machine is a part of.
@return [Environment]
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.
@return [String]
Name of the machine. This is assigned by the Vagrantfile.
@return [Symbol]
The provider backing this machine.
@return [Object]
The provider-specific configuration for this machine.
@return [Object]
The name of the provider.
@return [Symbol]
The options given to the provider when registering the plugin.
@return [Hash]
The UI for outputting in the scope of this machine.
@return [UI]
The Vagrantfile that this machine is attached to.
@return [Vagrantfile]
Initialize a new machine.
@param [String] name Name of the virtual machine. @param [Class] provider The provider backing this machine. This is
currently expected to be a V1 `provider` plugin.
@param [Object] #provider_config The provider-specific configuration for
this machine.
@param [Hash] #provider_options The provider-specific options from the
plugin definition.
@param [Object] config The configuration for this machine. @param [Pathname] #data_dir The directory where machine-specific data
can be stored. This directory is ensured to exist.
@param [Box] box The box that is backing this virtual machine. @param [Environment] env The environment that this machine is a
part of.
# File lib/vagrant/machine.rb, line 87 def initialize(name, provider_name, provider_cls, provider_config, provider_options, config, data_dir, box, env, vagrantfile, 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 @vagrantfile = vagrantfile @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 = Vagrant::UI::Prefixed.new(@env.ui, @name) @ui_mutex = Mutex.new # 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) @provider._initialize(@provider_name, self) end
This calls an action on the provider. The provider may or may not actually implement the action.
@param [Symbol] name Name of the action to run. @param [Hash] extra_env This data will be passed into the action runner
as extra data set on the environment hash for the middleware runner.
# File lib/vagrant/machine.rb, line 136 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
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.
@return [Object]
# File lib/vagrant/machine.rb, line 174 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
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.
@return [Guest]
# File lib/vagrant/machine.rb, line 190 def guest raise Errors::MachineGuestNotReady if !communicate.ready? @guest.detect! if !@guest.ready? @guest end
This sets the unique ID associated with this machine. This will persist this ID so that in the future Vagrant will be able to find this machine again. The unique ID must be absolutely unique to the virtual machine, and can be used by providers for finding the actual machine associated with this instance.
*WARNING:* Only providers should ever use this method.
@param [String] value The ID.
# File lib/vagrant/machine.rb, line 205 def id=(value) @logger.info("New machine ID: #{value.inspect}") # The file that will store the id if we have one. This allows the # ID to persist across Vagrant runs. id_file = @data_dir.join("id") if value # Write the "id" file with the id given. id_file.open("w+") do |f| f.write(value) end else # Delete the file, since the machine is now destroyed id_file.delete if id_file.file? # Delete the entire data directory contents since all state # associated with the VM is now gone. @data_dir.children.each do |child| begin child.rmtree rescue Errno::EACCES @logger.info("EACCESS deleting file: #{child}") end end end # Store the ID locally @id = value.nil? ? nil : value.to_s # Notify the provider that the ID changed in case it needs to do # any accounting from it. @provider.machine_id_changed end
This returns a clean inspect value so that printing the value via a pretty print (`p`) results in a readable value.
@return [String]
# File lib/vagrant/machine.rb, line 244 def inspect "#<#{self.class}: #{@name} (#{@provider.class})>" end
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.
@return [Hash] SSH information.
# File lib/vagrant/machine.rb, line 270 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 info[:password] = @config.ssh.password if @config.ssh.password # 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] && !info[:password] 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 # If we have a private key in our data dir, then use that if @data_dir data_private_key = @data_dir.join("private_key") if data_private_key.file? info[:private_key_path] = [data_private_key.to_s] end end # Setup the keys info[:private_key_path] ||= [] if !info[:private_key_path].is_a?(Array) info[:private_key_path] = [info[:private_key_path]] end # Expand the private key path relative to the root path info[:private_key_path].map! do |path| File.expand_path(path, @env.root_path) end # Return the final compiled SSH info data info end
Returns the state of this machine. The state is queried from the backing provider, so it can be any arbitrary symbol.
@return [MachineState]
# File lib/vagrant/machine.rb, line 340 def state result = @provider.state raise Errors::MachineStateInvalid if !result.is_a?(MachineState) result end