class Vagrant::Action::Builtin::Provision

This class will run the configured provisioners against the machine.

This action should be placed BEFORE the machine is booted so it can do some setup, and then run again (on the return path) against a running machine.

Public Class Methods

new(app, env) click to toggle source
# File lib/vagrant/action/builtin/provision.rb, line 17
def initialize(app, env)
  @app             = app
  @logger          = Log4r::Logger.new("vagrant::action::builtin::provision")
end

Public Instance Methods

call(env) click to toggle source
# File lib/vagrant/action/builtin/provision.rb, line 22
def call(env)
  @env = env

  # Check if we already provisioned, and if so, disable the rest
  enabled = true

  ignore_sentinel = true
  if env.has_key?(:provision_ignore_sentinel)
    ignore_sentinel = env[:provision_ignore_sentinel]
  end

  sentinel_path   = nil
  update_sentinel = false
  if !ignore_sentinel
    @logger.info("Checking provisioner sentinel if we should run...")
    sentinel_path = env[:machine].data_dir.join("action_provision")
    if sentinel_path.file?
      # The sentinel file is in the format of "version:data" so that
      # we can remain backwards compatible with previous sentinels.
      # Versions so far:
      #
      #   Vagrant < 1.5.0: A timestamp. The weakness here was that
      #     if it wasn't cleaned up, it would incorrectly not provision
      #     new machines.
      #
      #   Vagrant >= 1.5.0: "1.5:ID", where ID is the machine ID.
      #     We compare both so we know whether it is a new machine.
      #
      contents = sentinel_path.read.chomp
      parts    = contents.split(":", 2)

      if parts.length == 1
        @logger.info("Old-style sentinel found! Not provisioning.")
        enabled = false
        update_sentinel = true
      elsif parts[0] == "1.5" && parts[1] == env[:machine].id.to_s
        @logger.info("Sentinel found! Not provisioning.")
        enabled = false
      else
        @logger.info("Sentinel found with another machine ID. Removing.")
        sentinel_path.unlink
      end
    end
  end

  # Store the value so that other actions can use it
  env[:provision_enabled] = enabled if !env.has_key?(:provision_enabled)

  # Ask the provisioners to modify the configuration if needed
  provisioner_instances(env).each do |p|
    p.configure(env[:machine].config)
  end

  # Continue, we need the VM to be booted.
  @app.call(env)

  # Write the sentinel if we have to
  if sentinel_path
    if update_sentinel || !sentinel_path.file?
      @logger.info("Writing provisioning sentinel so we don't provision again")
      sentinel_path.open("w") do |f|
        f.write("1.5:#{env[:machine].id}")
      end
    end
  end

  # Actually provision if we enabled it
  if env[:provision_enabled]
    type_map = provisioner_type_map(env)
    provisioner_instances(env).each do |p|
      type_name = type_map[p]
      next if env[:provision_types] &&                  !env[:provision_types].include?(type_name)

      env[:ui].info(I18n.t(
        "vagrant.actions.vm.provision.beginning",
        provisioner: type_name))

      env[:hook].call(:provisioner_run, env.merge(
        callable: method(:run_provisioner),
        provisioner: p,
        provisioner_name: type_name,
      ))
    end
  elsif !enabled
    env[:ui].info(I18n.t("vagrant.actions.vm.provision.disabled_by_sentinel"))
  end
end
run_provisioner(env) click to toggle source

This is pulled out into a seperate method so that users can subclass and implement custom behavior if they'd like to work around this step.

# File lib/vagrant/action/builtin/provision.rb, line 114
def run_provisioner(env)
  env[:provisioner].provision
end