diff --git a/CHANGELOG.md b/CHANGELOG.md index e2568ccd309..6819b220d92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ method. - Default SSH host changed from `localhost` to `127.0.0.1` since `localhost` is not always loopback. + - New `shell` provisioner which simply uploads and executes a script as + root on the VM. ## 0.7.0 (January 19, 2011) diff --git a/lib/vagrant/provisioners.rb b/lib/vagrant/provisioners.rb index ccb53a43b65..5e963e4ce7d 100644 --- a/lib/vagrant/provisioners.rb +++ b/lib/vagrant/provisioners.rb @@ -6,3 +6,4 @@ require 'vagrant/provisioners/chef_solo' require 'vagrant/provisioners/puppet' require 'vagrant/provisioners/puppet_server' +require 'vagrant/provisioners/shell' diff --git a/lib/vagrant/provisioners/shell.rb b/lib/vagrant/provisioners/shell.rb new file mode 100644 index 00000000000..43f3d166025 --- /dev/null +++ b/lib/vagrant/provisioners/shell.rb @@ -0,0 +1,45 @@ +module Vagrant + module Provisioners + class Shell < Base + register :shell + + class Config < Vagrant::Config::Base + attr_accessor :path + attr_accessor :upload_path + + def initialize + @upload_path = "/tmp/vagrant-shell" + end + + def expanded_path + Pathname.new(path).expand_path(env.root_path) if path + end + + def validate(errors) + super + + if !path + errors.add(I18n.t("vagrant.provisioners.shell.path_not_set")) + elsif !expanded_path.file? + errors.add(I18n.t("vagrant.provisioners.shell.path_invalid", :path => expanded_path)) + end + + if !upload_path + errors.add(I18n.t("vagrant.provisioners.shell.upload_path_not_set")) + end + end + end + + def provision! + # Upload the script to the VM + vm.ssh.upload!(config.expanded_path.to_s, config.upload_path) + + # Execute it with sudo + vm.ssh.execute do |ssh| + ssh.sudo!("chmod +x #{config.upload_path}") + ssh.sudo!(config.upload_path) + end + end + end + end +end diff --git a/templates/locales/en.yml b/templates/locales/en.yml index fe376d4d548..548c5a10b8a 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -489,6 +489,11 @@ en: Puppet properly installed. running_puppetd: "Running Puppet agent..." + shell: + path_not_set: "`path` parameter pointing to script file to execute for shell provisioner is required" + path_invalid: "`path` for shell provisioner does not exist on the host system: %{path}" + upload_path_not_set: "`upload_path` must be set for the shell provisioner." + systems: base: unsupported_host_only: |- diff --git a/test/vagrant/provisioners/shell_test.rb b/test/vagrant/provisioners/shell_test.rb new file mode 100644 index 00000000000..0b39a292470 --- /dev/null +++ b/test/vagrant/provisioners/shell_test.rb @@ -0,0 +1,67 @@ +require "test_helper" + +class ShellProvisionerTest < Test::Unit::TestCase + setup do + clean_paths + + @klass = Vagrant::Provisioners::Shell + @action_env = Vagrant::Action::Environment.new(vagrant_env.vms[:default].env) + @config = @klass::Config.new + @config.top = Vagrant::Config::Top.new(@action_env.env) + @action = @klass.new(@action_env, @config) + + @config.path = "foo" + end + + context "config" do + setup do + @errors = Vagrant::Config::ErrorRecorder.new + + # Start in a valid state (verified by a test below) + @config.path = "foo" + File.open(@config.expanded_path, "w") { |f| f.puts "HELLO" } + end + + should "be valid" do + @config.validate(@errors) + assert @errors.errors.empty? + end + + should "be invalid if the path is not set" do + @config.path = nil + + @config.validate(@errors) + assert !@errors.errors.empty? + end + + should "be invalid if the path does not exist" do + @config.path = "bar" + + @config.validate(@errors) + assert !@errors.errors.empty? + end + + should "be invalid if the upload path is not set" do + @config.upload_path = nil + + @config.validate(@errors) + assert !@errors.errors.empty? + end + end + + context "provisioning" do + setup do + @ssh = mock("ssh") + @action.vm.ssh.stubs(:execute).yields(@ssh) + end + + should "upload the file, chmod, then execute it" do + p_seq = sequence("provisioning") + @action.vm.ssh.expects(:upload!).with(@config.expanded_path.to_s, @config.upload_path).in_sequence(p_seq) + @ssh.expects(:sudo!).with("chmod +x #{@config.upload_path}").in_sequence(p_seq) + @ssh.expects(:sudo!).with(@config.upload_path).in_sequence(p_seq) + + @action.provision! + end + end +end