Add Chef Apply provisioner
This commit is contained in:
parent
514101816b
commit
59eb0ad2e8
|
@ -0,0 +1,68 @@
|
|||
module VagrantPlugins
|
||||
module Chef
|
||||
module Config
|
||||
class ChefApply < Vagrant.plugin("2", :config)
|
||||
extend Vagrant::Util::Counter
|
||||
|
||||
# The raw recipe text (as a string) to execute via chef-apply.
|
||||
# @return [String]
|
||||
attr_accessor :recipe
|
||||
|
||||
# The path (on the guest) where the uploaded apply recipe should be
|
||||
# written (/tmp/vagrant-chef-apply-#.rb).
|
||||
# @return [String]
|
||||
attr_accessor :upload_path
|
||||
|
||||
# The Chef log level.
|
||||
# @return [String]
|
||||
attr_accessor :log_level
|
||||
|
||||
def initialize
|
||||
@recipe = UNSET_VALUE
|
||||
|
||||
@log_level = UNSET_VALUE
|
||||
@upload_path = UNSET_VALUE
|
||||
end
|
||||
|
||||
def finalize!
|
||||
@recipe = nil if @recipe == UNSET_VALUE
|
||||
|
||||
if @log_level == UNSET_VALUE
|
||||
@log_level = :info
|
||||
else
|
||||
@log_level = @log_level.to_sym
|
||||
end
|
||||
|
||||
if @upload_path == UNSET_VALUE
|
||||
counter = self.class.get_and_update_counter(:chef_apply)
|
||||
@upload_path = "/tmp/vagrant-chef-apply-#{counter}"
|
||||
end
|
||||
end
|
||||
|
||||
def validate(machine)
|
||||
errors = _detected_errors
|
||||
|
||||
if missing(recipe)
|
||||
errors << I18n.t("vagrant.provisioners.chef.recipe_empty")
|
||||
end
|
||||
|
||||
if missing(log_level)
|
||||
errors << I18n.t("vagrant.provisioners.chef.log_level_empty")
|
||||
end
|
||||
|
||||
if missing(upload_path)
|
||||
errors << I18n.t("vagrant.provisioners.chef.upload_path_empty")
|
||||
end
|
||||
|
||||
{ "chef apply provisioner" => errors }
|
||||
end
|
||||
|
||||
# Determine if the given string is "missing" (blank)
|
||||
# @return [true, false]
|
||||
def missing(obj)
|
||||
obj.to_s.strip.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -10,12 +10,12 @@ module VagrantPlugins
|
|||
name "chef"
|
||||
description <<-DESC
|
||||
Provides support for provisioning your virtual machines with
|
||||
Chef via `chef-solo` or `chef-client`.
|
||||
Chef via `chef-solo`, `chef-client`, or `chef-apply`.
|
||||
DESC
|
||||
|
||||
config(:chef_solo, :provisioner) do
|
||||
require_relative "config/chef_solo"
|
||||
Config::ChefSolo
|
||||
config(:chef_apply, :provisioner) do
|
||||
require_relative "config/chef_apply"
|
||||
Config::ChefApply
|
||||
end
|
||||
|
||||
config(:chef_client, :provisioner) do
|
||||
|
@ -23,14 +23,19 @@ module VagrantPlugins
|
|||
Config::ChefClient
|
||||
end
|
||||
|
||||
config(:chef_solo, :provisioner) do
|
||||
require_relative "config/chef_solo"
|
||||
Config::ChefSolo
|
||||
end
|
||||
|
||||
config(:chef_zero, :provisioner) do
|
||||
require_relative "config/chef_zero"
|
||||
Config::ChefZero
|
||||
end
|
||||
|
||||
provisioner(:chef_solo) do
|
||||
require_relative "provisioner/chef_solo"
|
||||
Provisioner::ChefSolo
|
||||
provisioner(:chef_apply) do
|
||||
require_relative "provisioner/chef_apply"
|
||||
Provisioner::ChefApply
|
||||
end
|
||||
|
||||
provisioner(:chef_client) do
|
||||
|
@ -38,6 +43,11 @@ module VagrantPlugins
|
|||
Provisioner::ChefClient
|
||||
end
|
||||
|
||||
provisioner(:chef_solo) do
|
||||
require_relative "provisioner/chef_solo"
|
||||
Provisioner::ChefSolo
|
||||
end
|
||||
|
||||
provisioner(:chef_zero) do
|
||||
require_relative "provisioner/chef_zero"
|
||||
Provisioner::ChefZero
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
require "tempfile"
|
||||
|
||||
module VagrantPlugins
|
||||
module Chef
|
||||
module Provisioner
|
||||
class ChefApply < Vagrant.plugin("2", :provisioner)
|
||||
def provision
|
||||
command = "chef-apply"
|
||||
command << " --log-level #{config.log_level}"
|
||||
command << " #{config.upload_path}"
|
||||
|
||||
user = @machine.ssh_info[:username]
|
||||
|
||||
# Reset upload path permissions for the current ssh user
|
||||
@machine.communicate.sudo("mkdir -p #{config.upload_path}")
|
||||
@machine.communicate.sudo("chown -R #{user} #{config.upload_path}")
|
||||
|
||||
# Upload the recipe
|
||||
upload_recipe
|
||||
|
||||
@machine.ui.info(I18n.t("vagrant.provisioners.chef.running_chef_apply",
|
||||
script: config.path)
|
||||
)
|
||||
|
||||
# Execute it with sudo
|
||||
@machine.communicate.sudo(command) do |type, data|
|
||||
if [:stderr, :stdout].include?(type)
|
||||
# Output the data with the proper color based on the stream.
|
||||
color = (type == :stdout) ? :green : :red
|
||||
|
||||
# Chomp the data to avoid the newlines that the Chef outputs
|
||||
@machine.env.ui.info(data.chomp, color: color, prefix: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Write the raw recipe contents to a tempfile and upload that to the
|
||||
# machine.
|
||||
def upload_recipe
|
||||
# Write the raw recipe contents to a tempfile
|
||||
file = Tempfile.new(["vagrant-chef-apply", ".rb"])
|
||||
file.write(config.recipe)
|
||||
file.rewind
|
||||
|
||||
# Upload the tempfile to the guest
|
||||
destination = File.join(config.upload_path, "recipe.rb")
|
||||
@machine.communicate.upload(file.path, destination)
|
||||
ensure
|
||||
# Delete our template
|
||||
file.close
|
||||
file.unlink
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1754,10 +1754,18 @@ en:
|
|||
"The cookbook path '%{path}' doesn't exist. Ignoring..."
|
||||
json: "Generating chef JSON and uploading..."
|
||||
client_key_folder: "Creating folder to hold client key..."
|
||||
log_level_empty: |-
|
||||
The Chef provisioner requires a log level. If you did not set a
|
||||
log level, this is probably a bug and should be reported.
|
||||
upload_validation_key: "Uploading chef client validation key..."
|
||||
upload_encrypted_data_bag_secret_key: "Uploading chef encrypted data bag secret key..."
|
||||
recipe_empty: |-
|
||||
Chef Apply provisioning requires that the `config.chef.recipe` be set
|
||||
to a string containing the recipe contents you want to execute on the
|
||||
guest.
|
||||
running_client: "Running chef-client..."
|
||||
running_client_again: "Running chef-client again (failed to converge)..."
|
||||
running_client_apply: "Running chef-apply..."
|
||||
running_solo: "Running chef-solo..."
|
||||
running_solo_again: "Running chef-solo again (failed to converge)..."
|
||||
missing_shared_folders: |-
|
||||
|
@ -1784,6 +1792,9 @@ en:
|
|||
server_validation_key_doesnt_exist: |-
|
||||
The validation key set for `config.chef.validation_key_path` does not exist! This
|
||||
file needs to exist so it can be uploaded to the virtual machine.
|
||||
upload_path_empty: |-
|
||||
The Chef Apply provisioner requires that the `config.chef.upload_path`
|
||||
be set to a non-nil, non-empty value.
|
||||
deleting_from_server: "Deleting %{deletable} \"%{name}\" from Chef server..."
|
||||
|
||||
file:
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
require_relative "../../../../base"
|
||||
|
||||
require Vagrant.source_root.join("plugins/provisioners/chef/config/chef_apply")
|
||||
|
||||
describe VagrantPlugins::Chef::Config::ChefApply do
|
||||
include_context "unit"
|
||||
|
||||
subject { described_class.new }
|
||||
|
||||
let(:machine) { double("machine") }
|
||||
|
||||
def chef_error(key, options = {})
|
||||
I18n.t("vagrant.provisioners.chef.#{key}", options)
|
||||
end
|
||||
|
||||
describe "#recipe" do
|
||||
it "defaults to nil" do
|
||||
subject.finalize!
|
||||
expect(subject.recipe).to be(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#log_level" do
|
||||
it "defaults to :info" do
|
||||
subject.finalize!
|
||||
expect(subject.log_level).to be(:info)
|
||||
end
|
||||
|
||||
it "is converted to a symbol" do
|
||||
subject.log_level = "foo"
|
||||
subject.finalize!
|
||||
expect(subject.log_level).to eq(:foo)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#upload_path" do
|
||||
it "defaults to /tmp/vagrant-chef-apply.rb" do
|
||||
subject.finalize!
|
||||
expect(subject.upload_path).to match(%r{/tmp/vagrant-chef-apply-\d+})
|
||||
end
|
||||
end
|
||||
|
||||
describe "#validate" do
|
||||
before do
|
||||
allow(machine).to receive(:env)
|
||||
.and_return(double("env",
|
||||
root_path: "",
|
||||
))
|
||||
|
||||
subject.recipe = <<-EOH
|
||||
package "foo"
|
||||
EOH
|
||||
end
|
||||
|
||||
let(:result) { subject.validate(machine) }
|
||||
let(:errors) { result["chef apply provisioner"] }
|
||||
|
||||
context "when the recipe is nil" do
|
||||
it "returns an error" do
|
||||
subject.recipe = nil
|
||||
subject.finalize!
|
||||
expect(errors).to include chef_error("recipe_empty")
|
||||
end
|
||||
end
|
||||
|
||||
context "when the recipe is empty" do
|
||||
it "returns an error" do
|
||||
subject.recipe = " "
|
||||
subject.finalize!
|
||||
expect(errors).to include chef_error("recipe_empty")
|
||||
end
|
||||
end
|
||||
|
||||
context "when the log_level is an empty array" do
|
||||
it "returns an error" do
|
||||
subject.log_level = " "
|
||||
subject.finalize!
|
||||
expect(errors).to include chef_error("log_level_empty")
|
||||
end
|
||||
end
|
||||
|
||||
context "when the upload_path is nil" do
|
||||
it "returns an error" do
|
||||
subject.upload_path = nil
|
||||
subject.finalize!
|
||||
expect(errors).to include chef_error("upload_path_empty")
|
||||
end
|
||||
end
|
||||
|
||||
context "when the upload_path is an empty array" do
|
||||
it "returns an error" do
|
||||
subject.upload_path = " "
|
||||
subject.finalize!
|
||||
expect(errors).to include chef_error("upload_path_empty")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue