Class: Vagrant::Machine
- Inherits:
-
Object
- Object
- Vagrant::Machine
- Extended by:
- Action::Builtin::MixinSyncedFolders
- Defined in:
- lib/vagrant/machine.rb,
lib/vagrant/machine/remote.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.).
Defined Under Namespace
Modules: Remote
Instance Attribute Summary collapse
-
#box ⇒ Box
The box that is backing this machine.
-
#config ⇒ Object
Configuration for the machine.
-
#data_dir ⇒ Pathname
readonly
Directory where machine-specific data can be stored.
-
#env ⇒ Environment
readonly
The environment that this machine is a part of.
-
#id ⇒ String
ID of the machine.
-
#name ⇒ Symbol
readonly
Name of the machine.
-
#provider ⇒ Object
readonly
The provider backing this machine.
-
#provider_config ⇒ Object
The provider-specific configuration for this machine.
-
#provider_name ⇒ Symbol
readonly
The name of the provider.
-
#provider_options ⇒ Hash
readonly
The options given to the provider when registering the plugin.
-
#triggers ⇒ Vagrant::Plugin::V2::Trigger
readonly
The triggers with machine specific configuration applied.
-
#ui ⇒ UI
readonly
The UI for outputting in the scope of this machine.
-
#vagrantfile ⇒ Vagrantfile
readonly
The Vagrantfile that this machine is attached to.
Instance Method Summary collapse
-
#action(name, opts = nil) ⇒ Object
This calls an action on the provider.
-
#action_raw(name, callable, extra_env = {}) ⇒ Hash
This calls a raw callable in the proper context of the machine using the middleware stack.
-
#communicate ⇒ Object
Returns a communication object for executing commands on the remote machine.
-
#guest ⇒ Guest
Returns a guest implementation for this machine.
-
#index_uuid ⇒ String
Returns the UUID associated with this machine in the machine index.
-
#initialize(name, provider_name, provider_cls, provider_config, provider_options, config, data_dir, box, env, vagrantfile, base = false) ⇒ Machine
constructor
Initialize a new machine.
-
#inspect ⇒ String
This returns a clean inspect value so that printing the value via a pretty print (
p
) results in a readable value. -
#recover_machine(state) ⇒ Entry
Returns the state of this machine.
-
#reload ⇒ Object
This reloads the ID of the underlying machine.
-
#ssh_info ⇒ Hash
This returns the SSH info for accessing this machine.
-
#state ⇒ MachineState
Returns the state of this machine.
-
#synced_folders ⇒ Hash<Symbol, Hash<String, Hash>>
This returns the set of shared folders that should be done for this machine.
-
#uid ⇒ String
Returns the user ID that created this machine.
-
#with_ui(ui) ⇒ Object
Temporarily changes the machine UI.
Methods included from Action::Builtin::MixinSyncedFolders
default_synced_folder_type, impl_opts, plugins, save_synced_folders, synced_folders_diff
Methods included from Util::ScopedHashOverride
Constructor Details
#initialize(name, provider_name, provider_cls, provider_config, provider_options, config, data_dir, box, env, vagrantfile, base = false) ⇒ Machine
Initialize a new machine.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/vagrant/machine.rb', line 102 def initialize(name, provider_name, provider_cls, provider_config, , 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 = @ui = Vagrant::UI::Prefixed.new(@env.ui, @name) @ui_mutex = Mutex.new @state_mutex = Mutex.new @triggers = Vagrant::Plugin::V2::Trigger.new(@env, @config.trigger, self, @ui) # 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 # For base setups, we don't want to insert the key @config.ssh.insert_key = false else reload end # Keep track of where our UUID should be placed @index_uuid_file = nil @index_uuid_file = @data_dir.join("index_uuid") if @data_dir # 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) # If we're using WinRM, we eager load the plugin because of # GH-3390 if @config.vm.communicator == :winrm @logger.debug("Eager loading WinRM communicator to avoid GH-3390") communicate end # If the ID is the special not created ID, then set our ID to # nil so that we destroy all our data. if state.id == MachineState::NOT_CREATED_ID self.id = nil end # Output a bunch of information about this machine in # machine-readable format in case someone is listening. @ui.machine("metadata", "provider", provider_name) end |
Instance Attribute Details
#box ⇒ Box
The box that is backing this machine.
23 24 25 |
# File 'lib/vagrant/machine.rb', line 23 def box @box end |
#config ⇒ Object
Configuration for the machine.
28 29 30 |
# File 'lib/vagrant/machine.rb', line 28 def config @config end |
#data_dir ⇒ Pathname (readonly)
Directory where machine-specific data can be stored.
33 34 35 |
# File 'lib/vagrant/machine.rb', line 33 def data_dir @data_dir end |
#env ⇒ Environment (readonly)
The environment that this machine is a part of.
38 39 40 |
# File 'lib/vagrant/machine.rb', line 38 def env @env end |
#id ⇒ String
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.
45 46 47 |
# File 'lib/vagrant/machine.rb', line 45 def id @id end |
#name ⇒ Symbol (readonly)
Name of the machine. This is assigned by the Vagrantfile.
50 51 52 |
# File 'lib/vagrant/machine.rb', line 50 def name @name end |
#provider ⇒ Object (readonly)
The provider backing this machine.
55 56 57 |
# File 'lib/vagrant/machine.rb', line 55 def provider @provider end |
#provider_config ⇒ Object
The provider-specific configuration for this machine.
60 61 62 |
# File 'lib/vagrant/machine.rb', line 60 def provider_config @provider_config end |
#provider_name ⇒ Symbol (readonly)
The name of the provider.
65 66 67 |
# File 'lib/vagrant/machine.rb', line 65 def provider_name @provider_name end |
#provider_options ⇒ Hash (readonly)
The options given to the provider when registering the plugin.
70 71 72 |
# File 'lib/vagrant/machine.rb', line 70 def @provider_options end |
#triggers ⇒ Vagrant::Plugin::V2::Trigger (readonly)
The triggers with machine specific configuration applied
75 76 77 |
# File 'lib/vagrant/machine.rb', line 75 def triggers @triggers end |
#ui ⇒ UI (readonly)
The UI for outputting in the scope of this machine.
80 81 82 |
# File 'lib/vagrant/machine.rb', line 80 def ui @ui end |
#vagrantfile ⇒ Vagrantfile (readonly)
The Vagrantfile that this machine is attached to.
85 86 87 |
# File 'lib/vagrant/machine.rb', line 85 def vagrantfile @vagrantfile end |
Instance Method Details
#action(name, opts = nil) ⇒ Object
This calls an action on the provider. The provider may or may not actually implement the action.
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/vagrant/machine.rb', line 174 def action(name, opts=nil) @logger.info("Calling action: #{name} on provider #{@provider}") opts ||= {} # Determine whether we lock or not lock = true lock = opts.delete(:lock) if opts.key?(:lock) # Extra env keys are the remaining opts extra_env = opts.dup check_cwd # Warns the UI if the machine was last used on a different dir # Create a deterministic ID for this machine vf = nil vf = @env.vagrantfile_name[0] if @env.vagrantfile_name id = Digest::MD5.hexdigest( "#{@env.root_path}#{vf}#{@env.local_data_path}#{@name}") # We only lock if we're not executing an SSH action. In the future # we will want to do more fine-grained unlocking in actions themselves # but for a 1.6.2 release this will work. locker = Proc.new { |*args, &block| block.call } locker = @env.method(:lock) if lock && !name.to_s.start_with?("ssh") # Lock this machine for the duration of this action return_env = locker.call("machine-action-#{id}") do # 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 # Call the action ui.machine("action", name.to_s, "start") action_result = action_raw(name, callable, extra_env) ui.machine("action", name.to_s, "end") action_result end # preserve returning environment after machine action runs return return_env rescue Errors::EnvironmentLockedError raise Errors::MachineActionLockedError, action: name, name: @name end |
#action_raw(name, callable, extra_env = {}) ⇒ Hash
This calls a raw callable in the proper context of the machine using the middleware stack.
234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/vagrant/machine.rb', line 234 def action_raw(name, callable, extra_env={}) if !extra_env.is_a?(Hash) extra_env = {} end # Run the action with the action runner on the environment env = {ui: @ui}.merge(extra_env).merge( raw_action_name: name, action_name: "machine_action_#{name}".to_sym, machine: self, machine_action: name ) @env.action_runner.run(callable, env) end |
#communicate ⇒ Object
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.
263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/vagrant/machine.rb', line 263 def communicate if !@communicator requested = @config.vm.communicator requested ||= :ssh klass = Vagrant.plugin("2").manager.communicators[requested] raise Errors::CommunicatorNotFound, comm: requested.to_s if !klass @communicator = klass.new(self) end @communicator end |
#guest ⇒ Guest
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.
280 281 282 283 284 |
# File 'lib/vagrant/machine.rb', line 280 def guest raise Errors::MachineGuestNotReady if !communicate.ready? @guest.detect! if !@guest.ready? @guest end |
#index_uuid ⇒ String
Returns the UUID associated with this machine in the machine index. We only have a UUID if an ID has been set.
389 390 391 392 393 |
# File 'lib/vagrant/machine.rb', line 389 def index_uuid return nil if !@index_uuid_file return @index_uuid_file.read.chomp if @index_uuid_file.file? return nil end |
#inspect ⇒ String
This returns a clean inspect value so that printing the value via
a pretty print (p
) results in a readable value.
399 400 401 |
# File 'lib/vagrant/machine.rb', line 399 def inspect "#<#{self.class}: #{@name} (#{@provider.class})>" end |
#recover_machine(state) ⇒ Entry
Returns the state of this machine. The state is queried from the backing provider, so it can be any arbitrary symbol.
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 |
# File 'lib/vagrant/machine.rb', line 572 def recover_machine(state) entry = @env.machine_index.get(index_uuid) if entry @env.machine_index.release(entry) return entry end entry = MachineIndex::Entry.new(id=index_uuid, {}) entry.local_data_path = @env.local_data_path entry.name = @name.to_s entry.provider = @provider_name.to_s entry.state = state entry.vagrantfile_path = @env.root_path entry.vagrantfile_name = @env.vagrantfile_name if @box entry.extra_data["box"] = { "name" => @box.name, "provider" => @box.provider.to_s, "architecture" => @box.architecture, "version" => @box.version.to_s, } end @state_mutex.synchronize do entry = @env.machine_index.recover(entry) @env.machine_index.release(entry) end return entry end |
#reload ⇒ Object
This reloads the ID of the underlying machine.
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
# File 'lib/vagrant/machine.rb', line 404 def reload old_id = @id @id = nil if @data_dir # 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_content = id_file.read.strip if id_file.file? if !id_content.to_s.empty? @id = id_content end end if @id != old_id && @provider # It changed, notify the provider @provider.machine_id_changed end @id end |
#ssh_info ⇒ Hash
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.
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 |
# File 'lib/vagrant/machine.rb', line 448 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[:keys_only] ||= @config.ssh.default.keys_only info[:verify_host_key] ||= @config.ssh.default.verify_host_key info[:username] ||= @config.ssh.default.username info[:remote_user] ||= @config.ssh.default.remote_user info[:compression] ||= @config.ssh.default.compression info[:dsa_authentication] ||= @config.ssh.default.dsa_authentication info[:extra_args] ||= @config.ssh.default.extra_args info[:config] ||= @config.ssh.default.config # 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[:keys_only] = @config.ssh.keys_only info[:verify_host_key] = @config.ssh.verify_host_key info[:compression] = @config.ssh.compression info[:dsa_authentication] = @config.ssh.dsa_authentication info[:username] = @config.ssh.username if @config.ssh.username info[:password] = @config.ssh.password if @config.ssh.password info[:remote_user] = @config.ssh.remote_user if @config.ssh.remote_user info[:extra_args] = @config.ssh.extra_args if @config.ssh.extra_args info[:config] = @config.ssh.config if @config.ssh.config # We also set some fields that are purely controlled by Vagrant info[:forward_agent] = @config.ssh.forward_agent info[:forward_x11] = @config.ssh.forward_x11 info[:forward_env] = @config.ssh.forward_env info[:connect_timeout] = @config.ssh.connect_timeout info[:ssh_command] = @config.ssh.ssh_command if @config.ssh.ssh_command # 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_paths end end # If we have a private key in our data dir, then use that if @data_dir && !@config.ssh.private_key_path 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] ||= [] info[:private_key_path] = Array(info[:private_key_path]) # Expand the private key path relative to the root path info[:private_key_path].map! do |path| File.(path, @env.root_path) end # Check that the private key permissions are valid info[:private_key_path].each do |path| key_path = Pathname.new(path) if key_path.exist? Vagrant::Util::SSH.(key_path) end end # Return the final compiled SSH info data info end |
#state ⇒ MachineState
Returns the state of this machine. The state is queried from the backing provider, so it can be any arbitrary symbol.
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 |
# File 'lib/vagrant/machine.rb', line 542 def state result = @provider.state raise Errors::MachineStateInvalid if !result.is_a?(MachineState) # Update our state cache if we have a UUID and an entry in the # master index. uuid = index_uuid if uuid # active_machines provides access to query this info on each machine # from a different thread, ensure multiple machines do not access # the locked entry simultaneously as this triggers a locked machine # exception. @state_mutex.synchronize do entry = @env.machine_index.get(uuid) if entry entry.state = result.short_description @env.machine_index.set(entry) @env.machine_index.release(entry) end end end result end |
#synced_folders ⇒ Hash<Symbol, Hash<String, Hash>>
This returns the set of shared folders that should be done for this machine. It returns the folders in a hash keyed by the implementation class for the synced folders.
633 634 635 |
# File 'lib/vagrant/machine.rb', line 633 def synced_folders self.class.synced_folders(self) end |
#uid ⇒ String
Returns the user ID that created this machine. This is specific to the host machine that this was created on.
607 608 609 610 611 612 |
# File 'lib/vagrant/machine.rb', line 607 def uid path = uid_file return nil if !path return nil if !path.file? return uid_file.read.chomp end |
#with_ui(ui) ⇒ Object
Temporarily changes the machine UI. This is useful if you want to execute an #action with a different UI.
616 617 618 619 620 621 622 623 624 625 626 |
# File 'lib/vagrant/machine.rb', line 616 def with_ui(ui) @ui_mutex.synchronize do begin old_ui = @ui @ui = ui yield ensure @ui = old_ui end end end |