vagrant-pirate 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ Feature: Init command
2
+
3
+ In order to start using a YAML-based Vagrant project
4
+ As a user using vagrant-pirate
5
+ I want to initialize a new project
6
+
7
+ Scenario: Running 'vagrant pirate ship'
8
+ Given a directory named "test"
9
+ And I cd to "test"
10
+ When I successfully run `vagrant pirate ship`
11
+ Then the following directories should exist:
12
+ | local.d |
13
+ | available.d |
14
+ | enabled.d |
15
+ And the following files should exist:
16
+ | Vagrantfile |
17
+ | available.d/default.yaml |
18
+ | enabled.d/vm1.yaml |
19
+ | enabled.d/vm2.yaml |
20
+ | local.d/vm1.yaml |
21
+ | local.d/vm2.yaml |
22
+ And the output should contain "A `Vagrantfile` has been placed in this directory, a default Yaml VM config file"
23
+ And the output should contain "has been placed in 'available.d', and a symlink to it, placed in 'enabled.d'."
24
+ And the output should contain "Finally, a file to contain local overrides was placed in 'local.d'. Unlike a"
25
+ And the output should contain "regular Vagrantfile, this one parses and applies the configuration in the Yaml"
26
+ And the output should contain "files it finds in 'enabled.d'. You are now ready to `vagrant up` your first"
27
+ And the output should contain "virtual environment! Please read the comments in the default Yaml VM config"
28
+ And the output should contain "file to see how it works."
@@ -0,0 +1,9 @@
1
+ # Since simplecov need to run in the same process as the code being annalized,
2
+ # we run initialize simplecov at the very beginning of our plugin. To only do
3
+ # so during tests, we wrap it in a check for an environment variable.
4
+ ENV['COVERAGE'] = 'true'
5
+ require 'coveralls'
6
+ # Since simplecov is running under a separate process, we need to retrieve the
7
+ # results afterwards.
8
+ Coveralls.wear_merged!
9
+ require 'aruba/cucumber'
@@ -0,0 +1,69 @@
1
+ require 'optparse'
2
+
3
+ module VagrantPlugins
4
+ module VagrantPirate
5
+ module Command
6
+ class Pirate < Vagrant.plugin("2", :command)
7
+ def self.synopsis
8
+ "Manage YAML-based projects."
9
+ end
10
+
11
+ def initialize(argv, env)
12
+ super
13
+
14
+ @main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
15
+
16
+ @subcommands = Vagrant::Registry.new
17
+ @subcommands.register(:ship) do
18
+ require File.expand_path("../pirate_ship", __FILE__)
19
+ PirateShip
20
+ end
21
+
22
+ @subcommands.register(:update) do
23
+ require File.expand_path("../pirate_update", __FILE__)
24
+ PirateUpdate
25
+ end
26
+ end
27
+
28
+ def execute
29
+ if @main_args.include?("-h") || @main_args.include?("--help")
30
+ # Print the help for all the box commands.
31
+ return help
32
+ end
33
+
34
+ # If we reached this far then we must have a subcommand. If not,
35
+ # then we also just print the help and exit.
36
+ command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
37
+ return help if !command_class || !@sub_command
38
+ @logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
39
+
40
+ # Initialize and execute the command class
41
+ command_class.new(@sub_args, @env).execute
42
+ end
43
+
44
+ # Prints the help out for this command
45
+ def help
46
+ opts = OptionParser.new do |opts|
47
+ opts.banner = "Usage: vagrant pirate <command> [<args>]"
48
+ opts.separator ""
49
+ opts.separator "Available subcommands:"
50
+
51
+ # Add the available subcommands as separators in order to print them
52
+ # out as well.
53
+ keys = []
54
+ @subcommands.each { |key, value| keys << key.to_s }
55
+
56
+ keys.sort.each do |key|
57
+ opts.separator " #{key}"
58
+ end
59
+
60
+ opts.separator ""
61
+ opts.separator "For help on any individual command run `vagrant pirate COMMAND -h`"
62
+ end
63
+
64
+ @env.ui.info(opts.help, :prefix => false)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,84 @@
1
+ require 'optparse'
2
+ require 'vagrant/util/template_renderer'
3
+
4
+ module VagrantPlugins
5
+ module VagrantPirate
6
+ module Command
7
+ class PirateShip < Vagrant.plugin("2", :command)
8
+
9
+ def self.synopsis
10
+ "Initializes a new Vagrant environment by creating a Vagrantfile and YAML config files."
11
+ end
12
+ def execute
13
+ options = {}
14
+
15
+ opts = OptionParser.new do |opts|
16
+ opts.banner = "Usage: vagrant pirate ship [box-name] [box-url]"
17
+ end
18
+
19
+ # Parse the options
20
+ argv = parse_options(opts)
21
+ return if !argv
22
+
23
+ create_vagrantfile
24
+ create_directories
25
+ create_default_yaml(argv[0], argv[1])
26
+ create_vm_yaml('vm1')
27
+ create_vm_yaml('vm2')
28
+
29
+ @env.ui.info(I18n.t(
30
+ "vagrant.plugins.pirate.commands.ship.success",
31
+ avail_dir: 'available.d',
32
+ enabled_dir: 'enabled.d',
33
+ local_dir: 'local.d'
34
+ ), :prefix => false)
35
+ # Success, exit status 0
36
+ 0
37
+ end
38
+
39
+ def create_vagrantfile
40
+ save_path = @env.cwd.join("Vagrantfile")
41
+ raise Errors::VagrantfileExistsError if save_path.exist?
42
+
43
+ template_path = ::VagrantPirate.source_root.join("templates/Vagrantfile")
44
+ contents = Vagrant::Util::TemplateRenderer.render(template_path)
45
+ save_path.open("w+") do |f|
46
+ f.write(contents)
47
+ end
48
+ end
49
+
50
+ def create_directories
51
+ Dir.mkdir('available.d')
52
+ Dir.mkdir('enabled.d')
53
+ Dir.mkdir('local.d')
54
+ end
55
+
56
+ def create_default_yaml(box_name=nil, box_url=nil)
57
+ save_path = @env.cwd.join("available.d/default.yaml")
58
+ raise Errors::VagrantfileExistsError if save_path.exist?
59
+
60
+ template_path = ::VagrantPirate.source_root.join("templates/default.yaml")
61
+ contents = Vagrant::Util::TemplateRenderer.render(template_path,
62
+ :box_name => box_name,
63
+ :box_url => box_url)
64
+ save_path.open("w+") do |f|
65
+ f.write(contents)
66
+ end
67
+ end
68
+
69
+ def create_vm_yaml(vm_name)
70
+ File.symlink("../available.d/default.yaml", "enabled.d/" + vm_name + ".yaml")
71
+ save_path = @env.cwd.join("local.d/" + vm_name + ".yaml")
72
+ raise Errors::VagrantfileExistsError if save_path.exist?
73
+ template_path = ::VagrantPirate.source_root.join("templates/local.yaml")
74
+ contents = Vagrant::Util::TemplateRenderer.render(template_path,
75
+ :hostname => vm_name + ".example.com")
76
+ save_path.open("w+") do |f|
77
+ f.write(contents)
78
+ end
79
+ end
80
+
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,77 @@
1
+ require 'optparse'
2
+ require 'vagrant/util/template_renderer'
3
+
4
+ module VagrantPlugins
5
+ module VagrantPirate
6
+ module Command
7
+ class PirateUpdate < Vagrant.plugin("2", :command)
8
+ def self.synopsis
9
+ "Updates a YAML-based Vagrant environment."
10
+ end
11
+
12
+ def execute
13
+ options = {}
14
+
15
+ # Boolean whether we should actually go through with the update
16
+ # or not. This is true only if the "--force" flag is set or if the
17
+ # user confirms it.
18
+ do_update = false
19
+
20
+ opts = OptionParser.new do |opts|
21
+ opts.banner = "Usage: vagrant pirate update"
22
+
23
+ opts.on("-f", "--force", "Update without confirmation.") do |f|
24
+ options[:force] = f
25
+ end
26
+ end
27
+
28
+ # Parse the options
29
+ argv = parse_options(opts)
30
+ return if !argv
31
+
32
+ if options[:force]
33
+ do_update = true
34
+ else
35
+ choice = nil
36
+ begin
37
+ choice = @env.ui.ask(I18n.t("vagrant.plugins.pirate.commands.update.confirmation"))
38
+
39
+ rescue Errors::UIExpectsTTY
40
+ # We raise a more specific error but one which basically
41
+ # means the same thing.
42
+ raise Errors::UpdateRequiresForce
43
+ end
44
+ do_update = choice.upcase == "Y"
45
+ end
46
+
47
+ if do_update
48
+ @logger.info("Updating project with latest Vagrantfile from vagrant-pirate.")
49
+ update
50
+ else
51
+ @logger.info("Not updating project since confirmation was declined.")
52
+ @env.ui.success(I18n.t("vagrant.plugins.pirate.commands.update.will_not_update"),
53
+ :prefix => false)
54
+ end
55
+ end
56
+
57
+ def update
58
+ save_path = @env.cwd.join("Vagrantfile")
59
+
60
+ template_path = ::VagrantPirate.source_root.join("templates/Vagrantfile")
61
+ contents = Vagrant::Util::TemplateRenderer.render(template_path)
62
+
63
+ # Write out the contents
64
+ save_path.open("w+") do |f|
65
+ f.write(contents)
66
+ end
67
+
68
+ @env.ui.info(I18n.t("vagrant.plugins.pirate.commands.update.success"),
69
+ :prefix => false)
70
+
71
+ # Success, exit status 0
72
+ 0
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,32 @@
1
+ module VagrantPlugins
2
+ module VagrantPirate
3
+ module Config
4
+ class Pirate < Vagrant.plugin("2", :config)
5
+ attr_accessor :map
6
+
7
+ def initialize
8
+ @map = UNSET_VALUE
9
+ end
10
+
11
+ def finalize!
12
+ if @map == UNSET_VALUE
13
+ @map = { "local" => "local.d", "enabled" => "vms-enabled" }
14
+ end
15
+ end
16
+
17
+ def validate(machine)
18
+ errors = _detected_errors
19
+ @map.each() do |name, conf_dir|
20
+ current_dir = Dir.pwd + '/' + conf_dir
21
+ if !File.directory?(current_dir)
22
+ errors << "Configuration directories must exist: #{current_dir}"
23
+ end
24
+ end
25
+
26
+ { "pirate" => errors }
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ module VagrantPirate
2
+ module Errors
3
+
4
+ class PirateError < Vagrant::Errors::VagrantError
5
+ def error_namespace; "vagrant.plugins.pirate.errors"; end
6
+ end
7
+
8
+ class VagrantfileExistsError < PirateError
9
+ error_key :vagrantfile_exists
10
+ end
11
+
12
+ class EnabledDirMissing < PirateError
13
+ error_key :enabled_dir_missing
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ require 'vagrant-pirate/vagrant-pirate'
2
+
3
+ module VagrantPlugins
4
+ module VagrantPirate
5
+ class Plugin < Vagrant.plugin("2")
6
+ name "Yagrant YAML"
7
+ description <<-DESC
8
+ This plugin enables Vagrant to use YAML files to configure VMs.
9
+ DESC
10
+
11
+ config("pirate") do
12
+ require_relative "config/pirate"
13
+ Config::Pirate
14
+ end
15
+
16
+ command("pirate") do
17
+ require_relative "command/pirate"
18
+ Command::Pirate
19
+ end
20
+
21
+ command("pirate-ship", primary: false) do
22
+ require_relative "command/pirate_ship"
23
+ Command::PirateShip
24
+ end
25
+
26
+ command("pirate-update", primary: false) do
27
+ require_relative "command/pirate_update"
28
+ Command::PirateUpdate
29
+ end
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,92 @@
1
+ module VagrantPirate
2
+ # The source root is the path to the root directory of the this gem.
3
+ def self.source_root
4
+ @source_root ||= Pathname.new(File.expand_path('../../../', __FILE__))
5
+ end
6
+
7
+ # Apply settings loaded from YAML to a vm.
8
+ def self.ahoy!(vm,yml)
9
+ yml.each do |key0,value0|
10
+ if !value0.is_a?(Hash) # If it's a setting,
11
+ vm.send("#{key0}=".to_sym, value0) # we set it directly.
12
+ else # Otherwise,
13
+ method_object = vm.method("#{key0}".to_sym) # we're invoking a method
14
+ value0.each do |key1,value1| # and each setting
15
+ method_object.call("#{key1}".to_sym, value1) # needs to be passed to the method.
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ # Merge hashes recursively
22
+ def self.sail_ho!(first, second)
23
+ second.each_pair do |k,v|
24
+ if first[k].is_a?(Hash) and second[k].is_a?(Hash)
25
+ deep_merge!(first[k], second[k])
26
+ else
27
+ first[k] = second[k]
28
+ end
29
+ end
30
+ end
31
+
32
+
33
+ def self.Arrr!(plunder)
34
+ require "yaml"
35
+
36
+ # Set defaults
37
+ local_dir = "local.d"
38
+ enabled_dir = "enabled.d"
39
+ # Override defaults with config, if it's set, since config finalizing
40
+ # occurs too late for our purposes.
41
+ if plunder.pirate.map.is_a?(Hash)
42
+ if plunder.pirate.map.has_key?('local')
43
+ local_dir = plunder.pirate.map['local']
44
+ end
45
+ if plunder.pirate.map.has_key?('enabled')
46
+ enabled_dir = plunder.pirate.map['enabled']
47
+ end
48
+ end
49
+
50
+ # All paths are relative to the project root
51
+ # todo: Can we access this from Vagrant::Environment?
52
+ current_dir = Dir.pwd
53
+ local_dir = "#{current_dir}/#{local_dir}"
54
+ enabled_dir = "#{current_dir}/#{enabled_dir}"
55
+
56
+ # Scan our vms-enabled/ directory for YAML config files
57
+ if File.directory?(enabled_dir)
58
+ config_files = Dir.glob("#{enabled_dir}/*.yaml")
59
+ else
60
+ raise Errors::EnabledDirMissing,
61
+ :enabled_dir => enabled_dir
62
+ end
63
+
64
+ # Build up a list of the VMs we'll provision, and their config_files
65
+ vms = {}
66
+ config_files.each do |config_file|
67
+ vms.update({ File.basename(config_file, ".yaml") => config_file})
68
+ end
69
+
70
+ # VM-specific configuration loaded from YAML config files
71
+ vms.each do |vm,config_file|
72
+
73
+ yml = YAML.load_file config_file
74
+ yml = {} if !yml.is_a?(Hash)
75
+
76
+ # Allow local overrides
77
+ local_file = "#{local_dir}/#{vm}.yaml"
78
+ if File.exists?(local_file)
79
+ local = YAML.load_file local_file
80
+ sail_ho!(yml, local) if local.is_a?(Hash)
81
+ end
82
+
83
+ plunder.vm.define "#{vm}" do |vm_config|
84
+ ahoy!(vm_config.vm, yml)
85
+ # We may need some project-wide config file to handle things like:
86
+ #vm_config.vbguest.auto_update = false
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,3 @@
1
+ module VagrantPirate
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,17 @@
1
+ # Since Vagrant starts under a different process from our tests, we need to
2
+ # initialize simplecov here, and make it available for coveralls to retrieve.
3
+ if ENV['COVERAGE']
4
+ require 'simplecov'
5
+ SimpleCov.command_name "binary #{Process.pid}"
6
+ SimpleCov.root(File.expand_path('../../', __FILE__))
7
+ SimpleCov.start
8
+ end
9
+
10
+
11
+ require 'vagrant'
12
+ require 'vagrant-pirate/errors'
13
+ require 'vagrant-pirate/plugin'
14
+ require 'vagrant-pirate/vagrant-pirate'
15
+
16
+ # Add our custom translations to the load path
17
+ I18n.load_path << File.expand_path("../../locales/en.yml", __FILE__)
data/locales/en.yml ADDED
@@ -0,0 +1,32 @@
1
+ en:
2
+ vagrant:
3
+ plugins:
4
+ pirate:
5
+ commands:
6
+ ship:
7
+ success: |-
8
+ A `Vagrantfile` has been placed in this directory, a default Yaml VM config file
9
+ has been placed in '%{avail_dir}', and a symlink to it, placed in '%{enabled_dir}'.
10
+ Finally, a file to contain local overrides was placed in '%{local_dir}'. Unlike a
11
+ regular Vagrantfile, this one parses and applies the configuration in the Yaml
12
+ files it finds in '%{enabled_dir}'. You are now ready to `vagrant up` your first
13
+ virtual environment! Please read the comments in the default Yaml VM config
14
+ file to see how it works.
15
+ update:
16
+ success: |-
17
+ Vagrantfile updated using the latest one from vagrant-pirate.
18
+ confirmation: |-
19
+ This operation will overwrite the Vagrantfile in this project with the one in the
20
+ vagrant-pirate gem. Do you want to proceed?
21
+ will_not_update: |-
22
+ User aborted. Vagrantfile was not updated.
23
+
24
+ errors:
25
+ vagrantfile_exists: |-
26
+ `Vagrantfile` already exists in this directory. Remove it before running `vagrant
27
+ pirate init`, or run `vagrant pirate update` to update to the latest version.
28
+ enabled_dir_missing: |-
29
+ A valid directory must be specified where YAML configs for the VMs can be found.
30
+ Current config points to a non-existent directory:
31
+ >>> %{enabled_dir}
32
+
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'cucumber'
3
+ require 'cucumber/rake/task'
4
+ require 'coveralls/rake/task'
5
+
6
+ desc 'Default task which runs all cucumber tests'
7
+ Coveralls::RakeTask.new
8
+ task :default => [:features, 'coveralls:push']
9
+ Cucumber::Rake::Task.new(:features) do |t|
10
+ t.cucumber_opts = "features --no-source --format pretty"
11
+ end
@@ -0,0 +1,16 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ # Vagrantfile API/syntax version.
5
+ # Don't be touching this, Matey, lest ye send us all down to Dany Jones' locker!
6
+ VAGRANTFILE_API_VERSION = "2"
7
+
8
+ Vagrant.configure(VAGRANTFILE_API_VERSION) do |plunder|
9
+
10
+ # Specify the directories in which to look for YAML VM config files.
11
+ #plunder.pirate.map = { 'local' => 'local.d', 'enabled' => 'enabled.d' }
12
+
13
+ # Load, parse and apply YAML VM configs.
14
+ Pirate::Arrr!(plunder)
15
+
16
+ end
@@ -0,0 +1,39 @@
1
+ # All Vagrant VM configuration can be done from Yaml config files such as this
2
+ # one. Only config files in the 'enabled.d' directory are interpreted. You
3
+ # can copy from, or symlink to, files in the 'available.d' directory. This
4
+ # allows you to have a library of config files that could, for example, be
5
+ # updated by an external application.
6
+
7
+ # Also, any Yaml config file in local.d/ named the same as one in enabled.d/
8
+ # will allow the selective override of individual configuration settings. See
9
+ # local.d/vm1.yaml for an example.
10
+
11
+ # To see what you can do with Yaml, check out this handy reference card:
12
+ # http://www.yaml.org/refcard.html. To see how Yaml is interpreted in Ruby, see
13
+ # this guide: http://yaml.org/YAML_for_ruby.html. For further details, refer to
14
+ # the full Yaml specification: http://www.yaml.org/spec/1.2/spec.html
15
+
16
+ # For all available Vagrant options, see the docs on Vagrantfile settings:
17
+ # http://vagrantup.com/v2/docs/vagrantfile.html. While we've provided some
18
+ # examples below, it's far from exhaustive. If you can't figure out how to
19
+ # apply a particular setting, please file a support request at:
20
+ # https://github.com/PraxisLabs/vagrant-pirate. Also, feel free to post to the
21
+ # project's wiki, or submit pull requests.
22
+
23
+ box: "<%= box_name || "base" %>"
24
+ <% if box_url.nil? %># <% end %>box_url: "<%= box_url || "http://domain.com/path/to/above.box" %>"
25
+ hostname: &id001 vagrant.local
26
+ #network:
27
+ # forwarded_port:
28
+ # :guest: 80
29
+ # :host: 8080
30
+ #provision:
31
+ # puppet:
32
+ # :module_path: 'modules'
33
+ # :manifests_path: 'manifests'
34
+ # :manifest_file: site.pp
35
+ # :options:
36
+ # - --verbose
37
+ # - --debug
38
+ # :facter:
39
+ # fqdn: *id001
@@ -0,0 +1,6 @@
1
+ # Any Yaml config file in 'local.d/' named the same as one in 'enabled.d/' will
2
+ # allow the selective override of individual configuration settings. Uncommen-
3
+ # ting the setting below would override the 'hostname' set by Vagrant in the
4
+ # VM.
5
+
6
+ hostname: <%= hostname %>
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/vagrant-pirate/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "vagrant-pirate"
6
+ s.version = VagrantPirate::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Christopher Gervais"]
9
+ s.email = ["chris@ergonlogic.com"]
10
+ s.license = 'GPL'
11
+ s.homepage = "https://github.com/PraxisLabs/vagrant-pirate"
12
+ s.summary = %q{A Vagrant plugin that allows configuration via YAML}
13
+ s.description = %q{A Vagrant plugin that allows configuration via YAML}
14
+
15
+ s.required_ruby_version = '>= 2.0.0'
16
+ s.required_rubygems_version = ">= 1.3.6"
17
+
18
+ s.add_development_dependency "cucumber"
19
+ s.add_development_dependency "aruba"
20
+ s.add_development_dependency "rake"
21
+ s.add_development_dependency "simplecov", '~> 0.7.1'
22
+ s.add_development_dependency "coveralls"
23
+
24
+ s.files = `git ls-files`.split("\n")
25
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
27
+ s.require_paths = ["lib"]
28
+
29
+ end