New provisioner API. Shell provisioner adheres to it.

This commit is contained in:
Mitchell Hashimoto 2013-01-13 15:48:52 -08:00
parent 25fcb59e38
commit c8053c00a4
4 changed files with 95 additions and 91 deletions

View File

@ -4,45 +4,42 @@ module Vagrant
# This is the base class for a provisioner for the V2 API. A provisioner # This is the base class for a provisioner for the V2 API. A provisioner
# is primarily responsible for installing software on a Vagrant guest. # is primarily responsible for installing software on a Vagrant guest.
class Provisioner class Provisioner
# The environment which provisioner is running in. This is the attr_reader :machine
# action environment, not a Vagrant::Environment.
attr_reader :env
# The configuration for this provisioner. This will be an instance of
# the `Config` class which is part of the provisioner.
attr_reader :config attr_reader :config
def initialize(env, config) # Initializes the provisioner with the machine that it will be
@env = env # provisioning along with the provisioner configuration (if there
@config = config # is any).
end
# This method is expected to return a class that is used for
# configuring the provisioner. This return value is expected to be
# a subclass of {Config}.
# #
# @return [Config] # The provisioner should _not_ do anything at this point except
def self.config_class # initialize internal state.
#
# @param [Machine] machine The machine that this will be provisioning.
# @param [Object] config Provisioner configuration, if one was set.
def initialize(machine, config)
@machine = machine
@config = config
end end
# This is the method called to "prepare" the provisioner. This is called # Called with the root configuration of the machine so the provisioner
# before any actions are run by the action runner (see {Vagrant::Actions::Runner}). # can add some configuration on top of the machine.
# This can be used to setup shared folders, forward ports, etc. Whatever is #
# necessary on a "meta" level. # During this step, and this step only, the provisioner should modify
# the root machine configuration to add any additional features it
# may need. Examples include sharing folders, networking, and so on.
# This step is guaranteed to be called before any of those steps are
# done so the provisioner may do that.
# #
# No return value is expected. # No return value is expected.
def prepare def configure(root_config)
end end
# This is the method called to provision the system. This method # This is the method called when the actual provisioning should be
# is expected to do whatever necessary to provision the system (create files, # done. The communicator is guaranteed to be ready at this point,
# SSH, etc.) # and any shared folders or networks are already setup.
def provision! #
end # No return value is expected.
def provision
# This is the method called to when the system is being destroyed
# and allows the provisioners to engage in any cleanup tasks necessary.
def cleanup
end end
end end
end end

View File

@ -0,0 +1,42 @@
module VagrantPlugins
module Shell
class Config < Vagrant.plugin("2", :config)
attr_accessor :inline
attr_accessor :path
attr_accessor :upload_path
attr_accessor :args
def initialize
@upload_path = "/tmp/vagrant-shell"
end
def validate(env, errors)
# Validate that the parameters are properly set
if path && inline
errors.add(I18n.t("vagrant.provisioners.shell.path_and_inline_set"))
elsif !path && !inline
errors.add(I18n.t("vagrant.provisioners.shell.no_path_or_inline"))
end
# Validate the existence of a script to upload
if path
expanded_path = Pathname.new(path).expand_path(env.root_path)
if !expanded_path.file?
errors.add(I18n.t("vagrant.provisioners.shell.path_invalid",
:path => expanded_path))
end
end
# There needs to be a path to upload the script to
if !upload_path
errors.add(I18n.t("vagrant.provisioners.shell.upload_path_not_set"))
end
# If there are args and its not a string, that is a problem
if args && !args.is_a?(String)
errors.add(I18n.t("vagrant.provisioners.shell.args_not_string"))
end
end
end
end
end

View File

@ -9,7 +9,12 @@ module VagrantPlugins
shell scripts. shell scripts.
DESC DESC
provisioner("shell") do config(:shell, :provisioner) do
require File.expand_path("../config", __FILE__)
Config
end
provisioner(:shell) do
require File.expand_path("../provisioner", __FILE__) require File.expand_path("../provisioner", __FILE__)
Provisioner Provisioner
end end

View File

@ -4,48 +4,32 @@ require "tempfile"
module VagrantPlugins module VagrantPlugins
module Shell module Shell
class Provisioner < Vagrant.plugin("2", :provisioner) class Provisioner < Vagrant.plugin("2", :provisioner)
class Config < Vagrant.plugin("2", :config) def provision
attr_accessor :inline args = ""
attr_accessor :path args = " #{config.args}" if config.args
attr_accessor :upload_path command = "chmod +x #{config.upload_path} && #{config.upload_path}#{args}"
attr_accessor :args
def initialize with_script_file do |path|
@upload_path = "/tmp/vagrant-shell" # Upload the script to the machine
end @machine.communicate.tap do |comm|
comm.upload(path.to_s, config.upload_path)
def validate(env, errors) # Execute it with sudo
# Validate that the parameters are properly set comm.sudo(command) do |type, data|
if path && inline if [:stderr, :stdout].include?(type)
errors.add(I18n.t("vagrant.provisioners.shell.path_and_inline_set")) # Output the data with the proper color based on the stream.
elsif !path && !inline color = type == :stdout ? :green : :red
errors.add(I18n.t("vagrant.provisioners.shell.no_path_or_inline"))
end
# Validate the existence of a script to upload # Note: Be sure to chomp the data to avoid the newlines that the
if path # Chef outputs.
expanded_path = Pathname.new(path).expand_path(env.root_path) @machine.env.ui.info(data.chomp, :color => color, :prefix => false)
if !expanded_path.file? end
errors.add(I18n.t("vagrant.provisioners.shell.path_invalid",
:path => expanded_path))
end end
end end
# There needs to be a path to upload the script to
if !upload_path
errors.add(I18n.t("vagrant.provisioners.shell.upload_path_not_set"))
end
# If there are args and its not a string, that is a problem
if args && !args.is_a?(String)
errors.add(I18n.t("vagrant.provisioners.shell.args_not_string"))
end
end end
end end
def self.config_class protected
Config
end
# This method yields the path to a script to upload and execute # This method yields the path to a script to upload and execute
# on the remote server. This method will properly clean up the # on the remote server. This method will properly clean up the
@ -53,7 +37,8 @@ module VagrantPlugins
def with_script_file def with_script_file
if config.path if config.path
# Just yield the path to that file... # Just yield the path to that file...
yield Pathname.new(config.path).expand_path(env[:root_path]) root_path = @machine.env.root_path
yield Pathname.new(config.path).expand_path(root_path)
return return
end end
@ -75,31 +60,6 @@ module VagrantPlugins
file.unlink file.unlink
end end
end end
def provision!
args = ""
args = " #{config.args}" if config.args
command = "chmod +x #{config.upload_path} && #{config.upload_path}#{args}"
with_script_file do |path|
# Upload the script to the machine
env[:machine].communicate.tap do |comm|
comm.upload(path.to_s, config.upload_path)
# Execute it with sudo
comm.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
# 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
end
end
end
end
end end
end end
end end