Class: Vagrant::Action::Builtin::Provision

Inherits:
Object
  • Object
show all
Includes:
MixinProvisioners
Defined in:
lib/vagrant/action/builtin/provision.rb

Overview

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.

Instance Method Summary collapse

Methods included from MixinProvisioners

#provisioner_instances

Constructor Details

#initialize(app, env) ⇒ Provision

Returns a new instance of Provision.


17
18
19
20
# File 'lib/vagrant/action/builtin/provision.rb', line 17

def initialize(app, env)
  @app             = app
  @logger          = Log4r::Logger.new("vagrant::action::builtin::provision")
end

Instance Method Details

#call(env) ⇒ Object


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
# File 'lib/vagrant/action/builtin/provision.rb', line 22

def call(env)
  @env = env

  # Tracks whether we were configured to provision
  config_enabled = true
  config_enabled = env[:provision_enabled] if env.key?(:provision_enabled)

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

  ignore_sentinel = true
  if env.key?(:provision_ignore_sentinel)
    ignore_sentinel = env[:provision_ignore_sentinel]
  end
  if ignore_sentinel
    @logger.info("Ignoring sentinel check, forcing provision")
  end

  @logger.info("Checking provisioner sentinel file...")
  sentinel_path = env[:machine].data_dir.join("action_provision")
  update_sentinel = false
  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.")
      provision_enabled = false if !ignore_sentinel
      update_sentinel = true
    elsif parts[0] == "1.5" && parts[1] == env[:machine].id.to_s
      @logger.info("Sentinel found! Not provisioning.")
      provision_enabled = false if !ignore_sentinel
    else
      @logger.info("Sentinel found with another machine ID. Removing.")
      sentinel_path.unlink
    end
  end

  # Store the value so that other actions can use it
  env[:provision_enabled] = provision_enabled if !env.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)

  # If we're configured to not provision, notify the user and stop
  if !config_enabled
    env[:ui].info(I18n.t("vagrant.actions.vm.provision.disabled_by_config"))
    return
  end

  # If we're not provisioning because of the sentinel, tell the user
  # but continue trying for the "always" provisioners
  if !provision_enabled
    env[:ui].info(I18n.t("vagrant.actions.vm.provision.disabled_by_sentinel"))
  end

  # Write the sentinel if we have to
  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

  type_map = provisioner_type_map(env)
  provisioner_instances(env).each do |p, options|
    type_name = type_map[p]

    if options[:run] == :never
      next if env[:provision_types].nil? || !env[:provision_types].include?(options[:name])
    else
      next if env[:provision_types] && \
        !env[:provision_types].include?(type_name) && \
        !env[:provision_types].include?(options[:name])

      # Don't run if sentinel is around and we're not always running
      next if !provision_enabled && options[:run] != :always
    end

    name = type_name
    if options[:name]
      name = "#{options[:name]} (#{type_name})"
    end

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

    env[:hook].call(:provisioner_run, env.merge(
      callable: method(:run_provisioner),
      provisioner: p,
      provisioner_name: type_name,
    ))
  end
end

#run_provisioner(env) ⇒ Object

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


137
138
139
# File 'lib/vagrant/action/builtin/provision.rb', line 137

def run_provisioner(env)
  env[:provisioner].provision
end