vagrant-recipe 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ # We depend on Vagrant for development, but we don't add it as a
7
+ # gem dependency because we expect to be installed within the
8
+ # Vagrant environment itself using `vagrant plugin`.
9
+ gem 'vagrant', git: 'git://github.com/mitchellh/vagrant.git'
10
+ end
data/LICENSE.md ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013-2013 Raul Simiciuc
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,87 @@
1
+ vagrant-recipe [![Gem Version](https://badge.fury.io/rb/vagrant-exec.png)](http://badge.fury.io/rb/vagrant-exec)
2
+ ===============
3
+
4
+ Vagrant plugin to execute chef recipes.
5
+
6
+ Description
7
+ -----------
8
+
9
+ Use this plugin to run your recipes at any time.
10
+
11
+ Example
12
+ -------
13
+
14
+ ```shell
15
+ ➜ vagrant run-recipe SystemSetup::default
16
+ ```
17
+
18
+ Installation
19
+ ------------
20
+
21
+ ```shell
22
+ ➜ vagrant plugin install vagrant-recipe
23
+ ```
24
+
25
+ Configuration
26
+ -------------
27
+
28
+ ### Chef exec file and chef json config file
29
+
30
+ The root directory can be configured using Vagrantfile.
31
+
32
+ ```ruby
33
+ Vagrant.configure('2') do |config|
34
+ config.vm.box = 'precise32'
35
+ # set this value if your solo exec file is different from /tmp/vagrant-chef-1/solo.rb
36
+ config.recipe.chef = '/tmp/vagrant-chef-1/solo.rb'
37
+
38
+ # set this value if your json confi file is different from /tmp/vagrant-chef-1/dna.json
39
+ config.recipe.json = '/tmp/vagrant-chef-1/dna.json'
40
+ end
41
+ ```
42
+
43
+ ```shell
44
+ ➜ vagrant run-recipe SystemSetup
45
+ # is the same as
46
+ ➜ vagrant ssh -c "sudo chef-solo -c /tmp/vagrant-chef-1/solo.rb -j /tmp/vagrant-chef-1/dna.json --override-runlist \"recipe[SystemSetup::default]\""
47
+ ```
48
+
49
+ ### Bundler
50
+
51
+ You can enable bundler to prepend each command with `bundle exec`. Note that it won't be done for commands starting with `bundle` (e.g. `bundle install`).
52
+
53
+ ```ruby
54
+ Vagrant.configure('2') do |config|
55
+ config.vm.box = 'precise32'
56
+ config.recipe.bundler = true
57
+ end
58
+ ```
59
+
60
+ ```shell
61
+ ➜ vagrant recipe SystemSetup
62
+ # is the same as
63
+ ➜ vagrant ssh -c "cd /vagrant && bundle exec sudo chef-solo -c /tmp/vagrant-chef-1/solo.rb -j /tmp/vagrant-chef-1/dna.json --override-runlist \"recipe[SystemSetup::default]\""
64
+ ```
65
+
66
+ ### Environment variables
67
+
68
+ You can add environment variables to be exported before.
69
+
70
+ ```ruby
71
+ Vagrant.configure('2') do |config|
72
+ config.vm.box = 'precise32'
73
+ config.recipe.env['RAILS_ENV'] = 'test'
74
+ config.recipe.env['RAILS_ROOT'] = '/vagrant'
75
+ end
76
+ ```
77
+
78
+ ```shell
79
+ ➜ vagrant exec SystemSetup
80
+ # is the same as
81
+ ➜ vagrant ssh -c "export RAILS_ENV=test && export RAILS_ROOT=/vagrant && sudo chef-solo -c /tmp/vagrant-chef-1/solo.rb -j /tmp/vagrant-chef-1/dna.json --override-runlist \"recipe[SystemSetup::default]\""
82
+ ```
83
+
84
+ Copyright
85
+ ---------
86
+
87
+ Copyright (c) 2013-2013 Raul Simiciuc. See LICENSE.md for details.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require 'bundler'
2
+ require 'cucumber/rake/task'
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ namespace :features do
6
+ desc 'Downloads and adds vagrant box for testing.'
7
+ task(:bootstrap) do
8
+ system('bundle exec vagrant box add vagrant_recipe http://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box')
9
+ end
10
+
11
+ Cucumber::Rake::Task.new(:run) do |t|
12
+ t.cucumber_opts = %w(--format pretty)
13
+ end
14
+
15
+ desc 'Removes testing vagrant box .'
16
+ task(:cleanup) do
17
+ system('bundle exec vagrant destroy -f')
18
+ system('bundle exec vagrant box remove vagrant_recipe virtualbox')
19
+ end
20
+ end
@@ -0,0 +1,49 @@
1
+ Given(/^I have default Vagrantfile$/) do
2
+ vagrantfile = <<-RUBY
3
+ Vagrant.require_plugin 'vagrant-exec'
4
+
5
+ Vagrant.configure('2') do |config|
6
+ config.vm.box = 'vagrant_exec'
7
+ end
8
+ RUBY
9
+ step 'a file named "Vagrantfile" with:', vagrantfile
10
+ end
11
+
12
+
13
+ Given(/^I set vagrant-exec folder to (.+)$/) do |folder|
14
+ config = <<-RUBY
15
+
16
+ Vagrant.configure('2') do |config|
17
+ config.exec.folder = #{folder}
18
+ end
19
+ RUBY
20
+ step 'I append to "Vagrantfile" with:', config
21
+ end
22
+
23
+
24
+ Given(/^I set vagrant-exec bundler to (.+)$/) do |bundler|
25
+ config = <<-RUBY
26
+
27
+ Vagrant.configure('2') do |config|
28
+ config.exec.bundler = #{bundler}
29
+ end
30
+ RUBY
31
+ step 'I append to "Vagrantfile" with:', config
32
+ end
33
+
34
+
35
+ Given(/^I set vagrant-exec env with the following values:$/) do |table|
36
+ data = table.hashes
37
+ config = data.map do |hash|
38
+ key, value = "#{hash['key']}", "#{hash['value']}"
39
+ %(config.exec.env['#{key}'] = '#{value}')
40
+ end
41
+
42
+ config = <<-RUBY
43
+
44
+ Vagrant.configure('2') do |config|
45
+ #{config.join("\n\s\s")}
46
+ end
47
+ RUBY
48
+ step 'I append to "Vagrantfile" with:', config
49
+ end
@@ -0,0 +1,12 @@
1
+ require 'aruba/cucumber'
2
+ ENV['VAGRANT_LOG'] = 'info'
3
+
4
+ Before do
5
+ # VM start takes a long time
6
+ @aruba_timeout_seconds = 60
7
+ end
8
+
9
+ After do
10
+ # halt VM
11
+ system "cd tmp/aruba; bundle exec vagrant halt &> /dev/null"
12
+ end
@@ -0,0 +1,91 @@
1
+ @no-clobber
2
+ Feature: vagrant-exec
3
+ In order to execute commands in Vagrant box
4
+ Within context of root synced folder
5
+ As a developer using vagrant-exec plugin
6
+ I want to use "vagrant exec" command
7
+ And be able to customize folder
8
+ And prepend commands with "bundle exec"
9
+ And set exported environmental variables
10
+ Using Vagrantfile configuration
11
+
12
+ Background:
13
+ Given I have default Vagrantfile
14
+
15
+ Scenario: uses /vagrant as default folder
16
+ Given I run `bundle exec vagrant up`
17
+ When I run `bundle exec vagrant exec pwd`
18
+ Then the exit status should be 0
19
+ And the output should contain "Executing single command on remote machine: cd /vagrant && pwd"
20
+
21
+ Scenario: can use custom folder
22
+ Given I set vagrant-exec folder to "/tmp"
23
+ And I run `bundle exec vagrant up`
24
+ When I run `bundle exec vagrant exec pwd`
25
+ Then the exit status should be 0
26
+ And the output should contain "Executing single command on remote machine: cd /tmp && pwd"
27
+
28
+ Scenario: raises error if folder is improperly set
29
+ Given I set vagrant-exec folder to true
30
+ And I run `bundle exec vagrant up`
31
+ Then the exit status should not be 0
32
+ And the output should contain "folder should be a string"
33
+
34
+ Scenario: does not use bundler by default
35
+ Given I run `bundle exec vagrant up`
36
+ When I run `bundle exec vagrant exec pwd`
37
+ Then the output should not contain "bundle exec"
38
+
39
+ # we don't have bundler in box
40
+ Scenario: can use bundler
41
+ Given I set vagrant-exec bundler to true
42
+ And I run `bundle exec vagrant up`
43
+ When I run `bundle exec vagrant exec pwd`
44
+ Then the exit status should not be 0
45
+ And the output should contain "Executing single command on remote machine: cd /vagrant && bundle exec pwd"
46
+
47
+ Scenario: does not use bundler for bundle commands
48
+ Given I set vagrant-exec bundler to true
49
+ And I run `bundle exec vagrant up`
50
+ When I run `bundle exec vagrant exec bundle install`
51
+ Then the output should contain "Executing single command on remote machine: cd /vagrant && bundle install"
52
+
53
+ Scenario: raises error if bundler is improperly set
54
+ Given I set vagrant-exec bundler to "true"
55
+ When I run `bundle exec vagrant up`
56
+ Then the exit status should not be 0
57
+ And the output should contain "bundler should be boolean"
58
+
59
+ Scenario: can export environment variables
60
+ Given I set vagrant-exec env with the following values:
61
+ | key | value |
62
+ | TEST1 | true |
63
+ | TEST2 | false |
64
+ And I run `bundle exec vagrant up`
65
+ When I run `bundle exec vagrant exec pwd`
66
+ Then the exit status should be 0
67
+ And the output should contain "Executing single command on remote machine: cd /vagrant && export TEST1=true && export TEST2=false && pwd"
68
+
69
+ Scenario Outline: shows help correctly
70
+ Given I run `bundle exec vagrant up`
71
+ When I run `bundle exec vagrant exec <args>`
72
+ Then the output should contain "Usage: vagrant exec [options] <command>"
73
+ Examples:
74
+ | args |
75
+ | |
76
+ | -h |
77
+ | --help |
78
+ | -h pwd |
79
+ | --help pwd -h |
80
+
81
+ Scenario Outline: passes command arguments correctly
82
+ Given I run `bundle exec vagrant up`
83
+ When I run `bundle exec vagrant exec <cmd>`
84
+ Then the output should contain "Executing single command on remote machine: cd /vagrant && <cmd>"
85
+ Examples:
86
+ | cmd |
87
+ | cwd . |
88
+ | cwd ~ |
89
+ | cwd -h |
90
+ | cwd --blah |
91
+ | cwd -h blah -v blah |
@@ -0,0 +1,72 @@
1
+ module VagrantPlugins
2
+ module Recipe
3
+ class Command < Vagrant.plugin(2, :command)
4
+
5
+ def execute
6
+ cmd, cmd_args = parse_args
7
+ cmd && cmd_args or return nil
8
+
9
+ # Execute the actual SSH
10
+ with_target_vms(nil, single_target: true) do |vm|
11
+ vm.config.recipe.finalize! # TODO: do we have to call it explicitly?
12
+
13
+ plain = "sudo chef-solo -c #{vm.config.recipe.chef} -j #{vm.config.recipe.json} --override-runlist \"recipe[#{cmd}]\""
14
+ command = ""
15
+
16
+ command << add_env(vm.config.exec.env)
17
+ command << add_bundler(vm.config.exec.bundler, plain)
18
+ command << plain
19
+
20
+ @logger.info("Executing recipe on remote machine: #{command}")
21
+ env = vm.action(:ssh_run, ssh_run_command: command)
22
+
23
+ status = env[:ssh_run_exit_status] || 0
24
+ return status
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def parse_args
31
+ opts = OptionParser.new do |o|
32
+ o.banner = 'Usage: vagrant run-recipe <recipe-name>'
33
+ o.separator ''
34
+
35
+ o.on('-h', '--help', 'Print this help') do
36
+ safe_puts(opts.help)
37
+ end
38
+ end
39
+
40
+ argv = split_main_and_subcommand(@argv.dup)
41
+ exec_args, cmd, cmd_args = argv[0], argv[1], argv[2]
42
+
43
+ # show help
44
+ if !cmd || exec_args.any? { |a| a == '-h' || a == '--help' }
45
+ safe_puts(opts.help)
46
+ return nil
47
+ end
48
+
49
+ return cmd, cmd_args
50
+ end
51
+
52
+ def add_env(env)
53
+ ''.tap do |command|
54
+ if env.any?
55
+ env.each do |key, value|
56
+ command << "export #{key}=#{value} && "
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def add_bundler(bundler, plain_command)
63
+ ''.tap do |command|
64
+ if bundler && plain_command !~ /^bundle /
65
+ command << 'bundle exec '
66
+ end
67
+ end
68
+ end
69
+
70
+ end # Command
71
+ end # Recipe
72
+ end # VagrantPlugins
@@ -0,0 +1,33 @@
1
+ module VagrantPlugins
2
+ module Recipe
3
+ class Config < Vagrant.plugin(2, :config)
4
+
5
+ attr_reader :env
6
+ attr_accessor :bundler
7
+ attr_accessor :chef
8
+ attr_accessor :json
9
+
10
+ def initialize
11
+ @env = {}
12
+ @bundler = UNSET_VALUE
13
+ @chef = UNSET_VALUE
14
+ @json = UNSET_VALUE
15
+ end
16
+
17
+ def validate(_)
18
+ return { 'exec' => ['bundler should be boolean'] } unless [true, false].include?(@bundler)
19
+ return { 'exec' => ['chef should be a string'] } unless @chef.is_a?(String)
20
+ return { 'exec' => ['json should be a string'] } unless @json.is_a?(String)
21
+
22
+ {}
23
+ end
24
+
25
+ def finalize!
26
+ @chef = '/tmp/vagrant-chef-1/solo.rb' if @chef == UNSET_VALUE
27
+ @json = '/tmp/vagrant-chef-1/dna.json' if @json == UNSET_VALUE
28
+ @bundler = false if @bundler == UNSET_VALUE
29
+ end
30
+
31
+ end # Config
32
+ end # Recipe
33
+ end # VagrantPlugins
@@ -0,0 +1,20 @@
1
+ module VagrantPlugins
2
+ module Recipe
3
+ class Plugin < Vagrant.plugin(2)
4
+
5
+ name 'Vagrant Recipe'
6
+ description 'Plugin allows to execute a chef recipe.'
7
+
8
+ config :run-recipe do
9
+ require_relative 'config'
10
+ Config
11
+ end
12
+
13
+ command :run-recipe do
14
+ require_relative 'command'
15
+ Command
16
+ end
17
+
18
+ end # Plugin
19
+ end # Recipe
20
+ end # VagrantPlugins
@@ -0,0 +1,7 @@
1
+ module VagrantPlugins
2
+ module Recipe
3
+
4
+ VERSION = '0.1.0'
5
+
6
+ end # Recipe
7
+ end # VagrantPlugins
@@ -0,0 +1,4 @@
1
+ require 'vagrant'
2
+
3
+ require 'vagrant-recipe/plugin'
4
+ require 'vagrant-recipe/version'
@@ -0,0 +1,21 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require 'vagrant-recipe/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'vagrant-recipe'
6
+ s.version = VagrantPlugins::Recipe::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.author = 'Raul Simiciuc'
9
+ s.email = 'byraul@gmail.com'
10
+ s.homepage = 'http://github.com/rsimiciuc/vagrant-recipe'
11
+ s.summary = 'Execute chef recipes'
12
+ s.description = 'Vagrant plugin to execute chef recipes'
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = %w(lib)
18
+
19
+ s.add_development_dependency 'aruba'
20
+ s.add_development_dependency 'rake'
21
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vagrant-recipe
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Raul Simiciuc
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-10-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: aruba
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Vagrant plugin to execute chef recipes
47
+ email: byraul@gmail.com
48
+ executables: []
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - Gemfile
53
+ - LICENSE.md
54
+ - README.md
55
+ - Rakefile
56
+ - features/step_definitions/steps.rb
57
+ - features/support/env.rb
58
+ - features/vagrant-recipe.feature
59
+ - lib/vagrant-recipe.rb
60
+ - lib/vagrant-recipe/command.rb
61
+ - lib/vagrant-recipe/config.rb
62
+ - lib/vagrant-recipe/plugin.rb
63
+ - lib/vagrant-recipe/version.rb
64
+ - vagrant-recipe.gemspec
65
+ homepage: http://github.com/rsimiciuc/vagrant-recipe
66
+ licenses: []
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubyforge_project:
85
+ rubygems_version: 1.8.23
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: Execute chef recipes
89
+ test_files: []