Skip to content

Commit

Permalink
Merge in 'flexible-provisioning' which supports abstracted provisione…
Browse files Browse the repository at this point in the history
…rs, chef server, additional chef solo features, and better chef configuration overall. Also includes pluggable configuration keys.
  • Loading branch information
mitchellh committed Mar 12, 2010
2 parents 9c8db3b + b86ef6a commit 9ba0647
Show file tree
Hide file tree
Showing 19 changed files with 867 additions and 170 deletions.
9 changes: 1 addition & 8 deletions config/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,8 @@
config.vm.project_directory = "/vagrant"
config.vm.forward_port("ssh", 22, 2222)
config.vm.disk_image_format = 'VMDK'
config.vm.provisioner = nil

config.package.name = 'vagrant'
config.package.extension = '.box'

config.chef.enabled = false
config.chef.cookbooks_path = "cookbooks"
config.chef.provisioning_path = "/tmp/vagrant-chef"
config.chef.json = {
:instance_role => "vagrant",
:recipes => ["vagrant_main"]
}
end
3 changes: 2 additions & 1 deletion lib/vagrant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

# The libs which must be loaded prior to the rest
%w{tempfile open-uri json pathname logger uri net/http virtualbox net/ssh archive/tar/minitar
net/scp fileutils vagrant/util vagrant/actions/base vagrant/downloaders/base vagrant/actions/runner}.each do |f|
net/scp fileutils vagrant/util vagrant/actions/base vagrant/downloaders/base vagrant/actions/runner
vagrant/config vagrant/provisioners/base vagrant/provisioners/chef}.each do |f|
require f
end

Expand Down
82 changes: 30 additions & 52 deletions lib/vagrant/actions/vm/provision.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,69 +2,47 @@ module Vagrant
module Actions
module VM
class Provision < Base
def prepare
Vagrant.config.vm.share_folder("vagrant-provisioning", cookbooks_path, File.expand_path(Vagrant.config.chef.cookbooks_path, Env.root_path))
end
attr_reader :provisioner

def execute!
chown_provisioning_folder
setup_json
setup_solo_config
run_chef_solo
end
def intialize(*args)
super

def chown_provisioning_folder
logger.info "Setting permissions on provisioning folder..."
SSH.execute do |ssh|
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
end
@provisioner = nil
end

def setup_json
logger.info "Generating JSON and uploading..."

# Set up initial configuration
data = {
:config => Vagrant.config,
:directory => Vagrant.config.vm.project_directory,
}

# And wrap it under the "vagrant" namespace
data = { :vagrant => data }

# Merge with the "extra data" which isn't put under the
# vagrant namespace by default
data.merge!(Vagrant.config.chef.json)

json = data.to_json
def prepare
provisioner = Vagrant.config.vm.provisioner

SSH.upload!(StringIO.new(json), File.join(Vagrant.config.chef.provisioning_path, "dna.json"))
end
if provisioner.nil?
logger.info("Provisioning not enabled, ignoring this step")
return
end

def setup_solo_config
solo_file = <<-solo
file_cache_path "#{Vagrant.config.chef.provisioning_path}"
cookbook_path "#{cookbooks_path}"
solo
if provisioner.is_a?(Class)
@provisioner = provisioner.new
raise ActionException.new("Provisioners must be an instance of Vagrant::Provisioners::Base") unless @provisioner.is_a?(Provisioners::Base)
elsif provisioner.is_a?(Symbol)
# We have a few hard coded provisioners for built-ins
mapping = {
:chef_solo => Provisioners::ChefSolo,
:chef_server => Provisioners::ChefServer
}

provisioner_klass = mapping[provisioner]
raise ActionException.new("Unknown provisioner type: #{provisioner}") if provisioner_klass.nil?
@provisioner = provisioner_klass.new
end

logger.info "Uploading chef-solo configuration script..."
SSH.upload!(StringIO.new(solo_file), File.join(Vagrant.config.chef.provisioning_path, "solo.rb"))
logger.info "Provisioning enabled with #{@provisioner.class}"
@provisioner.prepare
end

def run_chef_solo
logger.info "Running chef recipes..."
SSH.execute do |ssh|
ssh.exec!("cd #{Vagrant.config.chef.provisioning_path} && sudo chef-solo -c solo.rb -j dna.json") do |channel, data, stream|
# TODO: Very verbose. It would be easier to save the data and only show it during
# an error, or when verbosity level is set high
logger.info("#{stream}: #{data}")
end
def execute!
if provisioner
logger.info "Beginning provisioning process..."
provisioner.provision!
end
end

def cookbooks_path
File.join(Vagrant.config.chef.provisioning_path, "cookbooks")
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/vagrant/actions/vm/reload.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Reload < Base
def prepare
steps = [ForwardPorts, SharedFolders, Boot]
steps.unshift(Halt) if @runner.vm.running?
steps << Provision if Vagrant.config.chef.enabled
steps << Provision if !Vagrant.config.vm.provisioner.nil?

steps.each do |action_klass|
@runner.add_action(action_klass)
Expand Down
2 changes: 1 addition & 1 deletion lib/vagrant/actions/vm/up.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def prepare
# Up is a "meta-action" so it really just queues up a bunch
# of other actions in its place:
steps = [Import, ForwardPorts, SharedFolders, Boot]
steps << Provision if Vagrant.config.chef.enabled
steps << Provision if !Vagrant.config.vm.provisioner.nil?
steps.insert(0, MoveHardDrive) if Vagrant.config.vm.hd_location

steps.each do |action_klass|
Expand Down
25 changes: 3 additions & 22 deletions lib/vagrant/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def reset!
end

def configures(key, klass)
@@config.class.configures(key, klass)
config.class.configures(key, klass)
end

def config
Expand Down Expand Up @@ -75,11 +75,12 @@ class VMConfig < Base
attr_reader :shared_folders
attr_accessor :hd_location
attr_accessor :disk_image_format

attr_accessor :provisioner

def initialize
@forwarded_ports = {}
@shared_folders = {}
@provisioner = nil
end

def forward_port(name, guestport, hostport, protocol="TCP")
Expand Down Expand Up @@ -112,25 +113,6 @@ class PackageConfig < Base
attr_accessor :extension
end

class ChefConfig < Base
attr_accessor :cookbooks_path
attr_accessor :provisioning_path
attr_accessor :json
attr_accessor :enabled

def initialize
@enabled = false
end

def to_json
# Overridden so that the 'json' key could be removed, since its just
# merged into the config anyways
data = instance_variables_hash
data.delete(:json)
data.to_json
end
end

class VagrantConfig < Base
attr_accessor :dotfile_name
attr_accessor :log_output
Expand Down Expand Up @@ -159,7 +141,6 @@ def configures(key, klass)
configures :package, PackageConfig
configures :ssh, SSHConfig
configures :vm, VMConfig
configures :chef, ChefConfig
configures :vagrant, VagrantConfig

def initialize
Expand Down
22 changes: 22 additions & 0 deletions lib/vagrant/provisioners/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module Vagrant
module Provisioners
# The base class for a "provisioner." A provisioner is responsible for
# provisioning a Vagrant system. This has been abstracted out to provide
# support for multiple solutions such as Chef Solo, Chef Client, and
# Puppet.
class Base
include Vagrant::Util

# This is the method called to "prepare" the provisioner. This is called
# before any actions are run by the action runner (see {Vagrant::Actions::Runner}).
# This can be used to setup shared folders, forward ports, etc. Whatever is
# necessary on a "meta" level.
def prepare; end

# This is the method called to provision the system. This method
# is expected to do whatever necessary to provision the system (create files,
# SSH, etc.)
def provision!; end
end
end
end
102 changes: 102 additions & 0 deletions lib/vagrant/provisioners/chef.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
module Vagrant
module Provisioners
# This class is a base class where the common functinality shared between
# chef-solo and chef-client provisioning are stored. This is **not an actual
# provisioner**. Instead, {ChefSolo} or {ChefServer} should be used.
class Chef < Base
# This is the configuration which is available through `config.chef`
class ChefConfig < Vagrant::Config::Base
# Chef server specific config
attr_accessor :chef_server_url
attr_accessor :validation_key_path
attr_accessor :validation_client_name
attr_accessor :client_key_path

# Chef solo specific config
attr_accessor :cookbooks_path

# Shared config
attr_accessor :provisioning_path
attr_accessor :json

def initialize
@validation_client_name = "chef-validator"
@client_key_path = "/etc/chef/client.pem"

@cookbooks_path = "cookbooks"
@provisioning_path = "/tmp/vagrant-chef"
@json = {
:instance_role => "vagrant",
:run_list => ["recipe[vagrant_main]"]
}
end

# Returns the run list for the provisioning
def run_list
json[:run_list]
end

# Sets the run list to the specified value
def run_list=(value)
json[:run_list] = value
end

# Adds a recipe to the run list
def add_recipe(name)
name = "recipe[#{name}]" unless name =~ /^recipe\[(.+?)\]$/
run_list << name
end

# Adds a role to the run list
def add_role(name)
name = "role[#{name}]" unless name =~ /^role\[(.+?)\]$/
run_list << name
end

def to_json
# Overridden so that the 'json' key could be removed, since its just
# merged into the config anyways
data = instance_variables_hash
data.delete(:json)
data.to_json
end
end

# Tell the Vagrant configure class about our custom configuration
Config.configures :chef, ChefConfig

def prepare
raise Actions::ActionException.new("Vagrant::Provisioners::Chef is not a valid provisioner! Use ChefSolo or ChefServer instead.")
end

def chown_provisioning_folder
logger.info "Setting permissions on chef provisioning folder..."
SSH.execute do |ssh|
ssh.exec!("sudo mkdir -p #{Vagrant.config.chef.provisioning_path}")
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
end
end

def setup_json
logger.info "Generating chef JSON and uploading..."

# Set up initial configuration
data = {
:config => Vagrant.config,
:directory => Vagrant.config.vm.project_directory,
}

# And wrap it under the "vagrant" namespace
data = { :vagrant => data }

# Merge with the "extra data" which isn't put under the
# vagrant namespace by default
data.merge!(Vagrant.config.chef.json)

json = data.to_json

SSH.upload!(StringIO.new(json), File.join(Vagrant.config.chef.provisioning_path, "dna.json"))
end
end
end
end
Loading

0 comments on commit 9ba0647

Please sign in to comment.