Class: Vagrant::Environment

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

Overview

Represents a single Vagrant environment. A "Vagrant environment" is defined as basically a folder with a "Vagrantfile." This class allows access to the VMs, CLI, etc. all in the scope of this environment.

Constant Summary collapse

HOME_SUBDIRS =
["tmp", "boxes", "logs"]
DEFAULT_VM =
:default
DEFAULT_HOME =
"~/.vagrant.d"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = nil) ⇒ Environment

Initializes a new environment with the given options. The options is a hash where the main available key is cwd, which defines where the environment represents. There are other options available but they shouldn't be used in general. If cwd is nil, then it defaults to the Dir.pwd (which is the cwd of the executing process).



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
# File 'lib/vagrant/environment.rb', line 59

def initialize(opts=nil)
  opts = {
    :parent => nil,
    :vm => nil,
    :cwd => nil,
    :vagrantfile_name => nil,
    :lock_path => nil
  }.merge(opts || {})

  # Set the default working directory to look for the vagrantfile
  opts[:cwd] ||= Dir.pwd
  opts[:cwd] = Pathname.new(opts[:cwd])

  # Set the default vagrantfile name, which can be either Vagrantfile
  # or vagrantfile (capital for backwards compatibility)
  opts[:vagrantfile_name] ||= ["Vagrantfile", "vagrantfile"]
  opts[:vagrantfile_name] = [opts[:vagrantfile_name]] if !opts[:vagrantfile_name].is_a?(Array)

  opts.each do |key, value|
    instance_variable_set("@#{key}".to_sym, opts[key])
  end

  @loaded = false
  @lock_acquired = false

  logger.info("environment") { "Environment initialized (#{self})" }
  logger.info("environment") { "  - cwd: #{cwd}" }
  logger.info("environment") { "  - parent: #{parent}" }
  logger.info("environment") { "  - vm: #{vm}" }
end

Instance Attribute Details

#config_loaderObject (readonly)

The Config object representing the Vagrantfile loader



31
32
33
# File 'lib/vagrant/environment.rb', line 31

def config_loader
  @config_loader
end

#cwdObject (readonly)

The cwd that this environment represents



18
19
20
# File 'lib/vagrant/environment.rb', line 18

def cwd
  @cwd
end

#parentObject (readonly)

Parent environment (in the case of multi-VMs)



15
16
17
# File 'lib/vagrant/environment.rb', line 15

def parent
  @parent
end

#uiUI

Returns the UI for the environment, which is responsible for talking with the outside world.

Returns:



240
241
242
243
244
245
246
247
248
# File 'lib/vagrant/environment.rb', line 240

def ui
  @ui ||= if parent
    result = parent.ui.clone
    result.env = self
    result
  else
    UI.new(self)
  end
end

#vagrantfile_nameObject (readonly)

The valid name for a Vagrantfile for this environment.



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

def vagrantfile_name
  @vagrantfile_name
end

#vmObject

The single VM that this environment represents, in the case of multi-VM.



25
26
27
# File 'lib/vagrant/environment.rb', line 25

def vm
  @vm
end

Class Method Details

.check_virtualbox!Object

Verifies that VirtualBox is installed and that the version of VirtualBox installed is high enough.



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/vagrant/environment.rb', line 39

def check_virtualbox!
  version = VirtualBox.version
  raise Errors::VirtualBoxNotDetected if version.nil?
  raise Errors::VirtualBoxInvalidVersion, :version => version.to_s if version.to_f < 4.1 || version.to_f >= 4.2
rescue Errors::VirtualBoxNotDetected
  # On 64-bit Windows, show a special error. This error is a subclass
  # of VirtualBoxNotDetected, so libraries which use Vagrant can just
  # rescue VirtualBoxNotDetected.
  raise Errors::VirtualBoxNotDetected_Win64 if Util::Platform.windows? && Util::Platform.bit64?

  # Otherwise, reraise the old error
  raise
end

Instance Method Details

#actionsAction

Returns the Action class for this environment which allows actions to be executed (middleware chains) in the context of this environment.

Returns:



261
262
263
# File 'lib/vagrant/environment.rb', line 261

def actions
  @actions ||= Action.new(self)
end

#boxBox

Returns the box that this environment represents.

Returns:



177
178
179
# File 'lib/vagrant/environment.rb', line 177

def box
  boxes.find(config.vm.box)
end

#boxesBoxCollection

Returns the collection of boxes for the environment.

Returns:



169
170
171
172
# File 'lib/vagrant/environment.rb', line 169

def boxes
  return parent.boxes if parent
  @_boxes ||= BoxCollection.new(self)
end

#boxes_pathPathname

The path to the Vagrant boxes directory

Returns:

  • (Pathname)


145
146
147
# File 'lib/vagrant/environment.rb', line 145

def boxes_path
  home_path.join("boxes")
end

#cli(*args) ⇒ Object

Makes a call to the CLI with the given arguments as if they came from the real command line (sometimes they do!). An example:

env.cli("package", "--vagrantfile", "Vagrantfile")


232
233
234
# File 'lib/vagrant/environment.rb', line 232

def cli(*args)
  CLI.start(args.flatten, :env => self)
end

#configConfig::Top

The configuration object represented by this environment. This will trigger the environment to load if it hasn't loaded yet (see #load!).

Returns:



383
384
385
386
# File 'lib/vagrant/environment.rb', line 383

def config
  load! if !loaded?
  @config
end

#dotfile_pathPathname

The path to the dotfile, which contains the persisted UUID of the VM if it exists.

Returns:

  • (Pathname)


98
99
100
# File 'lib/vagrant/environment.rb', line 98

def dotfile_path
  root_path.join(config.vagrant.dotfile_name) rescue nil
end

#global_dataDataStore

Loads on initial access and reads data from the global data store. The global data store is global to Vagrant everywhere (in every environment), so it can be used to store system-wide information. Note that "system-wide" typically means "for this user" since the location of the global data store is in the home directory.

Returns:



272
273
274
275
# File 'lib/vagrant/environment.rb', line 272

def global_data
  return parent.global_data if parent
  @global_data ||= DataStore.new(File.expand_path("global_data.json", home_path))
end

#home_pathPathname

The path to the home directory and converted into a Pathname object.

Returns:

  • (Pathname)


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
# File 'lib/vagrant/environment.rb', line 105

def home_path
  return parent.home_path if parent
  return @_home_path if defined?(@_home_path)

  @_home_path ||= Pathname.new(File.expand_path(ENV["VAGRANT_HOME"] || DEFAULT_HOME))
  logger.info("environment") { "Home path: #{@_home_path}" }

  # This is the old default that Vagrant used to be put things into
  # up until Vagrant 0.8.0. We keep around an automatic migration
  # script here in case any old users upgrade.
  old_home = File.expand_path("~/.vagrant")
  if File.exists?(old_home) && File.directory?(old_home)
    logger.info("environment") { "Found both an old and new Vagrantfile. Migration initiated." }

    # We can't migrate if the home directory already exists
    if File.exists?(@_home_path)
      ui.warn I18n.t("vagrant.general.home_dir_migration_failed",
                     :old => old_home,
                     :new => @_home_path.to_s)
    else
      # If the new home path doesn't exist, simply transition to it
      ui.info I18n.t("vagrant.general.moving_home_dir", :directory => @_home_path)
      FileUtils.mv(old_home, @_home_path)
    end
  end

  # Return the home path
  @_home_path
end

#hostHosts::Base

Returns the host object associated with this environment.

Returns:



253
254
255
# File 'lib/vagrant/environment.rb', line 253

def host
  @host ||= Hosts::Base.load(self, config.vagrant.host)
end

#load!Object

Loads this entire environment, setting up the instance variables such as vm, config, etc. on this environment. The order this method calls its other methods is very particular.



403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
# File 'lib/vagrant/environment.rb', line 403

def load!
  if !loaded?
    @loaded = true

    if !parent
      # We only need to check the virtualbox version once, so do it on
      # the parent most environment and then forget about it
      logger.info("environment") { "Environment not loaded. Checking virtual box version..." }
      self.class.check_virtualbox!
    end

    logger.info("environment") { "Loading configuration..." }
    load_config!
  end

  self
end

#load_config!Object

Loads this environment's configuration and stores it in the #config variable. The configuration loaded by this method is specified to this environment, meaning that it will use the given root directory to load the Vagrantfile into that context.



433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
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
# File 'lib/vagrant/environment.rb', line 433

def load_config!
  first_run = @config.nil?

  # First load the initial, non config-dependent Vagrantfiles
  @config_loader ||= Config.new(parent ? parent.config_loader : nil)
  @config_loader.load_order = [:default, :box, :home, :root, :sub_vm]
  @config_loader.set(:default, File.expand_path("config/default.rb", Vagrant.source_root))

  vagrantfile_name.each do |rootfile|
    if !first_run && vm && box
      # We load the box Vagrantfile
      box_vagrantfile = box.directory.join(rootfile)
      @config_loader.set(:box, box_vagrantfile) if box_vagrantfile.exist?
    end

    if !first_run && home_path
      # Load the home Vagrantfile
      home_vagrantfile = home_path.join(rootfile)
      @config_loader.set(:home, home_vagrantfile) if home_vagrantfile.exist?
    end

    if root_path
      # Load the Vagrantfile in this directory
      root_vagrantfile = root_path.join(rootfile)
      @config_loader.set(:root, root_vagrantfile) if root_vagrantfile.exist?
    end
  end

  # If this environment is representing a sub-VM, then we push that
  # proc on as the last configuration.
  if vm
    subvm = parent.config.vm.defined_vms[vm.name]
    @config_loader.set(:sub_vm, subvm.proc_stack) if subvm
  end

  # Execute the configuration stack and store the result as the final
  # value in the config ivar.
  @config = @config_loader.load(self)

  if first_run
    # After the first run we want to load the configuration again since
    # it can change due to box Vagrantfiles and home directory Vagrantfiles
    load_home_directory!
    load_config!
  end
end

#load_home_directory!Object

Loads the home directory path and creates the necessary subdirectories within the home directory if they're not already created.



482
483
484
485
486
487
488
489
490
491
492
493
494
# File 'lib/vagrant/environment.rb', line 482

def load_home_directory!
  # Setup the array of necessary home directories
  dirs = [home_path]
  dirs += HOME_SUBDIRS.collect { |subdir| home_path.join(subdir) }

  # Go through each required directory, creating it if it doesn't exist
  dirs.each do |dir|
    next if File.directory?(dir)

    ui.info I18n.t("vagrant.general.creating_home_dir", :directory => dir)
    FileUtils.mkdir_p(dir)
  end
end

#load_vms!Object

Loads the persisted VM (if it exists) for this environment.



497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
# File 'lib/vagrant/environment.rb', line 497

def load_vms!
  result = {}

  # Load the VM UUIDs from the local data store
  (local_data[:active] || {}).each do |name, uuid|
    result[name.to_sym] = Vagrant::VM.find(uuid, self, name.to_sym)
  end

  # For any VMs which aren't created, create a blank VM instance for
  # them
  all_keys = config.vm.defined_vm_keys
  all_keys = [DEFAULT_VM] if all_keys.empty?
  all_keys.each do |name|
    result[name] = Vagrant::VM.new(:name => name, :env => self) if !result.has_key?(name)
  end

  result
end

#loaded?Bool

Returns a boolean representing if the environment has been loaded or not.

Returns:

  • (Bool)


396
397
398
# File 'lib/vagrant/environment.rb', line 396

def loaded?
  !!@loaded
end

#local_dataDataStore

Loads (on initial access) and reads data from the local data store. This file is always at the root path as the file "~/.vagrant" and contains a JSON dump of a hash. See DataStore for more information.

Returns:



283
284
285
286
# File 'lib/vagrant/environment.rb', line 283

def local_data
  return parent.local_data if parent
  @local_data ||= DataStore.new(dotfile_path)
end

#lockObject

This locks Vagrant for the duration of the block passed to this method. During this time, any other environment which attempts to lock which points to the same lock file will fail.



350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/vagrant/environment.rb', line 350

def lock
  # This allows multiple locks in the same process to be nested
  return yield if @lock_acquired

  File.open(lock_path, "w+") do |f|
    # The file locking fails only if it returns "false." If it
    # succeeds it returns a 0, so we must explicitly check for
    # the proper error case.
    raise Errors::EnvironmentLockedError if f.flock(File::LOCK_EX | File::LOCK_NB) === false

    begin
      # Mark that we have a lock
      @lock_acquired = true

      yield
    ensure
      # We need to make sure that no matter what this is always
      # reset to false so we don't think we have a lock when we
      # actually don't.
      @lock_acquired = false
    end
  end
end

#lock_pathObject

This returns the path which Vagrant uses to determine the location of the file lock. This is specific to each operating system.



343
344
345
# File 'lib/vagrant/environment.rb', line 343

def lock_path
  @lock_path || tmp_path.join("vagrant.lock")
end

#log_pathPathname

Path to the Vagrant logs directory

Returns:

  • (Pathname)


152
153
154
# File 'lib/vagrant/environment.rb', line 152

def log_path
  home_path.join("logs")
end

#loggerLogger

Accesses the logger for Vagrant. This logger is a detailed logger which should be used to log internals only. For outward facing information, use #ui.

Returns:

  • (Logger)


293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/vagrant/environment.rb', line 293

def logger
  return parent.logger if parent
  return @logger if @logger

  # Figure out where the output should go to.
  output = nil
  if ENV["VAGRANT_LOG"] == "STDOUT"
    output = STDOUT
  elsif ENV["VAGRANT_LOG"] == "NULL"
    output = nil
  elsif ENV["VAGRANT_LOG"]
    output = ENV["VAGRANT_LOG"]
  else
    output = nil #log_path.join("#{Time.now.to_i}.log")
  end

  # Create the logger and custom formatter
  @logger = Logger.new(output)
  @logger.formatter = Proc.new do |severity, datetime, progname, msg|
    "#{datetime} - #{progname} - [#{resource}] #{msg}\n"
  end

  @logger
end

#multivm?Bool

Returns a boolean whether this environment represents a multi-VM environment or not. This will work even when called on child environments.

Returns:

  • (Bool)


219
220
221
222
223
224
225
# File 'lib/vagrant/environment.rb', line 219

def multivm?
  if parent
    parent.multivm?
  else
    vms.length > 1 || vms.keys.first != DEFAULT_VM
  end
end

#primary_vmVM

Returns the primary VM associated with this environment. This method is only applicable for multi-VM environments. This can potentially be nil if no primary VM is specified.

Returns:



203
204
205
206
207
208
209
210
211
212
# File 'lib/vagrant/environment.rb', line 203

def primary_vm
  return vms.values.first if !multivm?
  return parent.primary_vm if parent

  config.vm.defined_vms.each do |name, subvm|
    return vms[name] if subvm.options[:primary]
  end

  nil
end

#reload_config!Object

Reloads the configuration of this environment.



422
423
424
425
426
427
# File 'lib/vagrant/environment.rb', line 422

def reload_config!
  @config = nil
  @config_loader = nil
  load_config!
  self
end

#resourceString

Returns the name of the resource which this environment represents. The resource is the VM name if there is a VM it represents, otherwise it defaults to "vagrant"

Returns:

  • (String)


161
162
163
164
# File 'lib/vagrant/environment.rb', line 161

def resource
  result = vm.name rescue nil
  result || "vagrant"
end

#root_pathString

The root path is the path where the top-most (loaded last) Vagrantfile resides. It can be considered the project root for this environment.

Returns:

  • (String)


323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/vagrant/environment.rb', line 323

def root_path
  return @root_path if defined?(@root_path)

  root_finder = lambda do |path|
    # Note: To remain compatible with Ruby 1.8, we have to use
    # a `find` here instead of an `each`.
    found = vagrantfile_name.find do |rootfile|
      File.exist?(File.join(path.to_s, rootfile))
    end

    return path if found
    return nil if path.root? || !File.exist?(path)
    root_finder.call(path.parent)
  end

  @root_path = root_finder.call(cwd)
end

#tmp_pathPathname

The path to the Vagrant tmp directory

Returns:

  • (Pathname)


138
139
140
# File 'lib/vagrant/environment.rb', line 138

def tmp_path
  home_path.join("tmp")
end

#vmsHash<Symbol,VM>

Returns the VMs associated with this environment.

Returns:

  • (Hash<Symbol,VM>)


184
185
186
187
188
# File 'lib/vagrant/environment.rb', line 184

def vms
  return parent.vms if parent
  load! if !loaded?
  @vms ||= load_vms!
end

#vms_orderedArray<VM>

Returns the VMs associated with this environment, in the order that they were defined.

Returns:

  • (Array<VM>)


194
195
196
# File 'lib/vagrant/environment.rb', line 194

def vms_ordered
  @vms_enum ||= config.vm.defined_vm_keys.map { |name| @vms[name] }
end