vagrant-pirate 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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