File: vagrant.rb

package info (click to toggle)
vagrant 2.3.7%2Bgit20230731.5fc64cde%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 17,616 kB
  • sloc: ruby: 111,820; sh: 462; makefile: 123; ansic: 34; lisp: 1
file content (362 lines) | stat: -rw-r--r-- 12,784 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
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
166
167
168
169
170
171
172
173
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
require "log4r"

# Add patches to log4r to support trace level
require "vagrant/patches/log4r"
# Set our log levels and include trace
require 'log4r/configurator'
Log4r::Configurator.custom_levels(*(["TRACE"] + Log4r::Log4rConfig::LogLevels))

# Update the default formatter within the log4r library to ensure
# sensitive values are being properly scrubbed from logger data
class Log4r::BasicFormatter
  alias_method :vagrant_format_object, :format_object
  def format_object(obj)
    Vagrant::Util::CredentialScrubber.desensitize(vagrant_format_object(obj))
  end
end

require "optparse"

module Vagrant
  # This is a customized OptionParser for Vagrant plugins. It
  # will automatically add any default CLI options defined
  # outside of command implementations to the local option
  # parser instances in use
  class OptionParser < ::OptionParser
    def initialize(*_)
      super
      Vagrant.default_cli_options.each do |opt_proc|
        opt_proc.call(self)
      end
    end
  end
end

# Inject the option parser into the vagrant plugins
# module so it is automatically used when defining
# command options
module VagrantPlugins
  OptionParser = Vagrant::OptionParser
end

# Load in our helpers and utilities
require "vagrant/shared_helpers"
require "rubygems"
require "vagrant/util"
require "vagrant/plugin/manager"

# Enable logging if it is requested. We do this before
# anything else so that we can setup the output before
# any logging occurs.
if ENV["VAGRANT_LOG"] && ENV["VAGRANT_LOG"] != ""
  level = Log4r::LNAMES.index(ENV["VAGRANT_LOG"].upcase)
  if level.nil?
    level = Log4r::LNAMES.index("FATAL")
  end

  if !level
    # We directly write to stderr here because the VagrantError system
    # is not setup yet.
    $stderr.puts "Invalid VAGRANT_LOG level is set: #{ENV["VAGRANT_LOG"]}"
    $stderr.puts ""
    $stderr.puts "Please use one of the standard log levels: debug, info, warn, or error"
    exit 1
  end

  # Set the logging level on all "vagrant" namespaced
  # logs as long as we have a valid level.
  if level
    # NOTE: We must do this little hack to allow
    # rest-client to write using the `<<` operator.
    # See https://github.com/rest-client/rest-client/issues/34#issuecomment-290858
    # for more information
    class VagrantLogger < Log4r::Logger
      def << msg
        debug(msg.strip)
      end
    end

    ["vagrant", "vagrantplugins"].each do |lname|
      logger = VagrantLogger.new(lname)
      if ENV["VAGRANT_LOG_FILE"] && ENV["VAGRANT_LOG_FILE"] != ""
        logger.outputters = Log4r::FileOutputter.new("vagrant", filename: ENV["VAGRANT_LOG_FILE"])
      else
        logger.outputters = Log4r::Outputter.stderr
      end
      logger.level = level
    end

    base_formatter = Log4r::BasicFormatter.new
    if ENV["VAGRANT_LOG_TIMESTAMP"]
      base_formatter = Log4r::PatternFormatter.new(
        pattern: "%d [%5l] %m",
        date_pattern: "%F %T"
      )
    end

    Log4r::Outputter.stderr.formatter = Vagrant::Util::LoggingFormatter.new(base_formatter)
  end
end

require 'json'
require 'pathname'
require 'stringio'

require 'childprocess'
require 'i18n'

# OpenSSL must be loaded here since when it is loaded via `autoload`
# there are issues with ciphers not being properly loaded.
require 'openssl'

# Always make the version available
require 'vagrant/version'
global_logger = Log4r::Logger.new("vagrant::global")
Vagrant.global_logger = global_logger
global_logger.info("Vagrant version: #{Vagrant::VERSION}")
global_logger.info("Ruby version: #{RUBY_VERSION}")
global_logger.info("RubyGems version: #{Gem::VERSION}")
ENV.each do |k, v|
  next if k.start_with?("VAGRANT_OLD")
  global_logger.info("#{k}=#{v.inspect}") if k.start_with?("VAGRANT_")
end

# If the vagrant_ssl library exists, a recent version
# of openssl is in use and its needed to load all the
# providers needed
if File.exist?(File.expand_path("vagrant/vagrant_ssl.so", __dir__))
  global_logger.debug("vagrant ssl helper found for loading ssl providers")
  begin
    require "vagrant/vagrant_ssl"
    Vagrant.vagrant_ssl_load
    global_logger.debug("ssl providers successfully loaded")
  rescue LoadError => err
    global_logger.warn("failed to load ssl providers, attempting to continue (#{err})")
  rescue => err
    global_logger.warn("unexpected failure loading ssl providers, attempting to continue (#{err})")
  end
end

# We need these components always so instead of an autoload we
# just require them explicitly here.
require "vagrant/plugin"
require "vagrant/registry"

module Vagrant
  autoload :Action,         'vagrant/action'
  autoload :Alias,          'vagrant/alias'
  autoload :BatchAction,    'vagrant/batch_action'
  autoload :Box,            'vagrant/box'
  autoload :BoxCollection,  'vagrant/box_collection'
  autoload :BoxMetadata,    'vagrant/box_metadata'
  autoload :Bundler,        'vagrant/bundler'
  autoload :CLI,            'vagrant/cli'
  autoload :CapabilityHost, 'vagrant/capability_host'
  autoload :Config,         'vagrant/config'
  autoload :Environment,    'vagrant/environment'
  autoload :Errors,         'vagrant/errors'
  autoload :Guest,          'vagrant/guest'
  autoload :Host,           'vagrant/host'
  autoload :Machine,        'vagrant/machine'
  autoload :MachineIndex,   'vagrant/machine_index'
  autoload :MachineState,   'vagrant/machine_state'
  autoload :Plugin,         'vagrant/plugin'
  autoload :Registry,       'vagrant/registry'
  autoload :UI,             'vagrant/ui'
  autoload :Util,           'vagrant/util'
  autoload :Vagrantfile,    'vagrant/vagrantfile'
  autoload :VERSION,        'vagrant/version'

  # These are the various plugin versions and their components in
  # a lazy loaded Hash-like structure.
  PLUGIN_COMPONENTS = Registry.new.tap do |c|
    c.register(:"1")                  { Plugin::V1::Plugin }
    c.register([:"1", :command])      { Plugin::V1::Command }
    c.register([:"1", :communicator]) { Plugin::V1::Communicator }
    c.register([:"1", :config])       { Plugin::V1::Config }
    c.register([:"1", :guest])        { Plugin::V1::Guest }
    c.register([:"1", :host])         { Plugin::V1::Host }
    c.register([:"1", :provider])     { Plugin::V1::Provider }
    c.register([:"1", :provisioner])  { Plugin::V1::Provisioner }

    c.register(:"2")                  { Plugin::V2::Plugin }
    c.register([:"2", :command])      { Plugin::V2::Command }
    c.register([:"2", :communicator]) { Plugin::V2::Communicator }
    c.register([:"2", :config])       { Plugin::V2::Config }
    c.register([:"2", :guest])        { Plugin::V2::Guest }
    c.register([:"2", :host])         { Plugin::V2::Host }
    c.register([:"2", :provider])     { Plugin::V2::Provider }
    c.register([:"2", :provisioner])  { Plugin::V2::Provisioner }
    c.register([:"2", :push])         { Plugin::V2::Push }
    c.register([:"2", :synced_folder]) { Plugin::V2::SyncedFolder }

    c.register(:remote)               { Plugin::Remote::Plugin }
  end

  # Configure a Vagrant environment. The version specifies the version
  # of the configuration that is expected by the block. The block, based
  # on that version, configures the environment.
  #
  # Note that the block isn't run immediately. Instead, the configuration
  # block is stored until later, and is run when an environment is loaded.
  #
  # @param [String] version Version of the configuration
  def self.configure(version, &block)
    Config.run(version, &block)
  end

  # This checks if a plugin with the given name is available (installed
  # and enabled). This can be used from the Vagrantfile to easily branch
  # based on plugin availability.
  def self.has_plugin?(name, version=nil)
    return false unless Vagrant.plugins_enabled?

    if !version
      # We check the plugin names first because those are cheaper to check
      return true if plugin("2").manager.registered.any? { |p| p.name == name }
    end

    # Now check the plugin gem names
    require "vagrant/plugin/manager"
    Plugin::Manager.instance.plugin_installed?(name, version)
  end

  # Returns a superclass to use when creating a plugin for Vagrant.
  # Given a specific version, this returns a proper superclass to use
  # to register plugins for that version.
  #
  # Optionally, if you give a specific component, then it will return
  # the proper superclass for that component as well.
  #
  # Plugins and plugin components should subclass the classes returned by
  # this method. This method lets Vagrant core control these superclasses
  # and change them over time without affecting plugins. For example, if
  # the V1 superclass happens to be "Vagrant::V1," future versions of
  # Vagrant may move it to "Vagrant::Plugins::V1" and plugins will not be
  # affected.
  #
  # @param [String] version
  # @param [String] component
  # @return [Class]
  def self.plugin(version, component=nil)
    # Build up the key and return a result
    key    = version.to_s.to_sym
    key    = [key, component.to_s.to_sym] if component
    result = PLUGIN_COMPONENTS.get(key)

    # If we found our component then we return that
    return result if result

    # If we didn't find a result, then raise an exception, depending
    # on if we got a component or not.
    raise ArgumentError, "Plugin superclass not found for version/component: " +
      "#{version} #{component}"
  end

  # @deprecated
  def self.require_plugin(name)
    puts "Vagrant.require_plugin is deprecated and has no effect any longer."
    puts "Use `vagrant plugin` commands to manage plugins. This warning will"
    puts "be removed in the next version of Vagrant."
  end

  # This checks if Vagrant is installed in a specific version.
  #
  # Example:
  #
  #    Vagrant.version?(">= 2.1.0")
  #
  def self.version?(*requirements)
    req = Gem::Requirement.new(*requirements)
    req.satisfied_by?(Gem::Version.new(VERSION))
  end

  # This allows a Vagrantfile to specify the version of Vagrant that is
  # required. You can specify a list of requirements which will all be checked
  # against the running Vagrant version.
  #
  # This should be specified at the _top_ of any Vagrantfile.
  #
  # Examples are shown below:
  #
  #   Vagrant.require_version(">= 1.3.5")
  #   Vagrant.require_version(">= 1.3.5", "< 1.4.0")
  #   Vagrant.require_version("~> 1.3.5")
  #
  def self.require_version(*requirements)
    logger = Log4r::Logger.new("vagrant::root")
    logger.info("Version requirements from Vagrantfile: #{requirements.inspect}")

    if version?(*requirements)
      logger.info("  - Version requirements satisfied!")
      return
    end

    raise Errors::VagrantVersionBad,
      requirements: requirements.join(", "),
      version: VERSION
  end

  # This allows plugin developers to access the original environment before
  # Vagrant even ran. This is useful when shelling out, especially to other
  # Ruby processes.
  #
  # @return [Hash]
  def self.original_env
    {}.tap do |h|
      ENV.each do |k,v|
        if k.start_with?("VAGRANT_OLD_ENV")
          key = k.sub(/^VAGRANT_OLD_ENV_/, "")
          if !key.empty?
            h[key] = v
          end
        end
      end
    end
  end
end

# Default I18n to load the en locale
I18n.load_path << File.expand_path("templates/locales/en.yml", Vagrant.source_root)

if I18n.config.respond_to?(:enforce_available_locales=)
  # Make sure only available locales are used. This will be the default in the
  # future but we need this to silence a deprecation warning from 0.6.9
  I18n.config.enforce_available_locales = true
end

if Vagrant.enable_resolv_replace
  global_logger.info("resolv replacement has been enabled!")
else
  global_logger.warn("resolv replacement has not been enabled!")
end

# A lambda that knows how to load plugins from a single directory.
plugin_load_proc = lambda do |directory|
  # We only care about directories
  next false if !directory.directory?

  # If there is a plugin file in the top-level directory, then load
  # that up.
  plugin_file = directory.join("plugin.rb")
  if plugin_file.file?
    global_logger.debug("Loading core plugin: #{plugin_file}")
    load(plugin_file)
    next true
  end
end

# Go through the `plugins` directory and attempt to load any plugins. The
# plugins are allowed to be in a directory in `plugins` or at most one
# directory deep within the plugins directory. So a plugin can be at
# `plugins/foo` or also at `plugins/foo/bar`, but no deeper.
Vagrant.source_root.join("plugins").children(true).each do |directory|
  # Ignore non-directories
  next if !directory.directory?

  # Load from this directory, and exit if we successfully loaded a plugin
  next if plugin_load_proc.call(directory)

  # Otherwise, attempt to load from sub-directories
  directory.children(true).each(&plugin_load_proc)
end