Class: Vagrant::Provisioners::ChefSolo

Inherits:
Chef
  • Object
show all
Extended by:
Util::Counter
Includes:
Util::Counter
Defined in:
lib/vagrant/provisioners/chef_solo.rb

Overview

This class implements provisioning via chef-solo.

Defined Under Namespace

Classes: Config

Instance Attribute Summary collapse

Attributes inherited from Base

#config, #env

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util::Counter

get_and_update_counter, mutex

Methods inherited from Chef

#chef_binary_path, #chown_provisioning_folder, #setup_config, #setup_json, #verify_binary

Methods inherited from Base

#cleanup

Constructor Details

#initialize(env, config) ⇒ ChefSolo

Returns a new instance of ChefSolo.



62
63
64
65
# File 'lib/vagrant/provisioners/chef_solo.rb', line 62

def initialize(env, config)
  super
  @logger = Log4r::Logger.new("vagrant::provisioners::chef_solo")
end

Instance Attribute Details

#cookbook_foldersObject (readonly)

Returns the value of attribute cookbook_folders.



54
55
56
# File 'lib/vagrant/provisioners/chef_solo.rb', line 54

def cookbook_folders
  @cookbook_folders
end

#data_bags_foldersObject (readonly)

Returns the value of attribute data_bags_folders.



56
57
58
# File 'lib/vagrant/provisioners/chef_solo.rb', line 56

def data_bags_folders
  @data_bags_folders
end

#role_foldersObject (readonly)

Returns the value of attribute role_folders.



55
56
57
# File 'lib/vagrant/provisioners/chef_solo.rb', line 55

def role_folders
  @role_folders
end

Class Method Details

.config_classObject



58
59
60
# File 'lib/vagrant/provisioners/chef_solo.rb', line 58

def self.config_class
  Config
end

Instance Method Details

#encrypted_data_bag_secret_key_pathObject



222
223
224
# File 'lib/vagrant/provisioners/chef_solo.rb', line 222

def encrypted_data_bag_secret_key_path
  File.expand_path(config.encrypted_data_bag_secret_key_path, env[:root_path])
end

#expanded_folders(paths, appended_folder = nil) ⇒ Object

Converts paths to a list of properly expanded paths with types.



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
# File 'lib/vagrant/provisioners/chef_solo.rb', line 100

def expanded_folders(paths, appended_folder=nil)
  return [] if paths.nil?

  # Convert the path to an array if it is a string or just a single
  # path element which contains the folder location (:host or :vm)
  paths = [paths] if paths.is_a?(String) || paths.first.is_a?(Symbol)

  results = []
  paths.each do |path|
    path = [:host, path] if !path.is_a?(Array)
    type, path = path

    # Create the local/remote path based on whether this is a host
    # or VM path.
    local_path = nil
    remote_path = nil
    if type == :host
      # Get the expanded path that the host path points to
      local_path = File.expand_path(path, env[:root_path])

      # Super hacky but if we're expanded the default cookbook paths,
      # and one of the host paths doesn't exist, then just ignore it,
      # because that is fine.
      if paths.equal?(config._default_cookbook_path) && !File.directory?(local_path)
        @logger.info("'cookbooks' folder doesn't exist on defaults. Ignoring.")
        next
      end

      # Path exists on the host, setup the remote path
      remote_path = "#{config.provisioning_path}/chef-solo-#{get_and_update_counter(:cookbooks_path)}"
    else
      # Path already exists on the virtual machine. Expand it
      # relative to where we're provisioning.
      remote_path = File.expand_path(path, config.provisioning_path)

      # Remove drive letter if running on a windows host. This is a bit
      # of a hack but is the most portable way I can think of at the moment
      # to achieve this. Otherwise, Vagrant attempts to share at some crazy
      # path like /home/vagrant/c:/foo/bar
      remote_path = remote_path.gsub(/^[a-zA-Z]:/, "")
    end

    # If we have specified a folder name to append then append it
    remote_path += "/#{appended_folder}" if appended_folder

    # Append the result
    results << [type, local_path, remote_path]
  end

  results
end

#prepareObject



67
68
69
70
71
72
73
74
75
# File 'lib/vagrant/provisioners/chef_solo.rb', line 67

def prepare
  @cookbook_folders = expanded_folders(config.cookbooks_path, "cookbooks")
  @role_folders = expanded_folders(config.roles_path, "roles")
  @data_bags_folders = expanded_folders(config.data_bags_path, "data_bags")

  share_folders("csc", @cookbook_folders)
  share_folders("csr", @role_folders)
  share_folders("csdb", @data_bags_folders)
end

#provision!Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/vagrant/provisioners/chef_solo.rb', line 77

def provision!
  # Verify that the proper shared folders exist.
  check = []
  [@cookbook_folders, @role_folders, @data_bags_folders].each do |folders|
    folders.each do |type, local_path, remote_path|
      # We only care about checking folders that have a local path, meaning
      # they were shared from the local machine, rather than assumed to
      # exist on the VM.
      check << remote_path if local_path
    end
  end

  verify_shared_folders(check)

  verify_binary(chef_binary_path("chef-solo"))
  chown_provisioning_folder
  upload_encrypted_data_bag_secret if config.encrypted_data_bag_secret_key_path
  setup_json
  setup_solo_config
  run_chef_solo
end

#run_chef_soloObject

Raises:



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
# File 'lib/vagrant/provisioners/chef_solo.rb', line 185

def run_chef_solo
  command_env = config.binary_env ? "#{config.binary_env} " : ""
  command = "#{command_env}#{chef_binary_path("chef-solo")} -c #{config.provisioning_path}/solo.rb -j #{config.provisioning_path}/dna.json"

  config.attempts.times do |attempt|
    if attempt == 0
      env[:ui].info I18n.t("vagrant.provisioners.chef.running_solo")
    else
      env[:ui].info I18n.t("vagrant.provisioners.chef.running_solo_again")
    end

    exit_status = env[:vm].channel.sudo(command, :error_check => false) do |type, data|
      # Output the data with the proper color based on the stream.
      color = type == :stdout ? :green : :red

      # Note: Be sure to chomp the data to avoid the newlines that the
      # Chef outputs.
      env[:ui].info(data.chomp, :color => color, :prefix => false)
    end

    # There is no need to run Chef again if it converges
    return if exit_status == 0
  end

  # If we reached this point then Chef never converged! Error.
  raise ChefError, :no_convergence
end

#setup_solo_configObject



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/vagrant/provisioners/chef_solo.rb', line 169

def setup_solo_config
  cookbooks_path = guest_paths(@cookbook_folders)
  roles_path = guest_paths(@role_folders).first
  data_bags_path = guest_paths(@data_bags_folders).first

  setup_config("provisioners/chef_solo/solo", "solo.rb", {
    :node_name => config.node_name,
    :provisioning_path => config.provisioning_path,
    :cookbooks_path => cookbooks_path,
    :recipe_url => config.recipe_url,
    :roles_path => roles_path,
    :data_bags_path => data_bags_path,
    :encrypted_data_bag_secret => config.encrypted_data_bag_secret,
  })
end

#share_folders(prefix, folders) ⇒ Object

Shares the given folders with the given prefix. The folders should be of the structure resulting from the expanded_folders function.



154
155
156
157
158
159
160
161
# File 'lib/vagrant/provisioners/chef_solo.rb', line 154

def share_folders(prefix, folders)
  folders.each do |type, local_path, remote_path|
    if type == :host
      env[:vm].config.vm.share_folder("v-#{prefix}-#{self.class.get_and_update_counter(:shared_folder)}",
                                 remote_path, local_path, :nfs => config.nfs)
    end
  end
end

#upload_encrypted_data_bag_secretObject



163
164
165
166
167
# File 'lib/vagrant/provisioners/chef_solo.rb', line 163

def upload_encrypted_data_bag_secret
  env[:ui].info I18n.t("vagrant.provisioners.chef.upload_encrypted_data_bag_secret_key")
  env[:vm].channel.upload(encrypted_data_bag_secret_key_path,
                          config.encrypted_data_bag_secret)
end

#verify_shared_folders(folders) ⇒ Object



213
214
215
216
217
218
219
220
# File 'lib/vagrant/provisioners/chef_solo.rb', line 213

def verify_shared_folders(folders)
  folders.each do |folder|
    @logger.debug("Checking for shared folder: #{folder}")
    if !env[:vm].channel.test("test -d #{folder}")
      raise ChefError, :missing_shared_folders
    end
  end
end