vagrant-orchestrate 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.rubocop.yml +18 -0
- data/Gemfile +14 -0
- data/LICENSE +13 -0
- data/README.md +57 -0
- data/Rakefile +4 -0
- data/lib/vagrant-orchestrate/command/init.rb +145 -0
- data/lib/vagrant-orchestrate/command/push.rb +35 -0
- data/lib/vagrant-orchestrate/command/root.rb +74 -0
- data/lib/vagrant-orchestrate/plugin.rb +62 -0
- data/lib/vagrant-orchestrate/version.rb +5 -0
- data/lib/vagrant-orchestrate.rb +12 -0
- data/locales/en.yml +0 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/vagrant-orchestrate/command/init_spec.rb +198 -0
- data/spec/vagrant-orchestrate/command/root_spec.rb +27 -0
- data/templates/vagrant/Vagrantfile.erb +45 -0
- data/vagrant-orchestrate.gemspec +25 -0
- metadata +108 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 85f4c2c23fc36ac0e8c472263b585d736444cde7
|
4
|
+
data.tar.gz: d85359d431acc54e007e5089e97b5391dc2af394
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 14e2b97efed9fd854b9abdb285869780a8e9145f07747105da88e902c73845e4b50d779c9e1059d70d8d59cd4b071181abe419a5ea55f95dd6e954a6a7f96208
|
7
|
+
data.tar.gz: bcfe1a59b4013c6905132bced3e6dc9f3617b5edb3594e268ea32ac81e34c846a3191a88ae14c7380cd14f0d2b122402da117bdf345f31035e400433a9dff51a
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- '*.gemspec'
|
4
|
+
|
5
|
+
Metrics/LineLength:
|
6
|
+
Max: 120
|
7
|
+
|
8
|
+
Style/Documentation:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Metrics/MethodLength:
|
12
|
+
Max: 20
|
13
|
+
|
14
|
+
StringLiterals:
|
15
|
+
EnforcedStyle: double_quotes
|
16
|
+
|
17
|
+
Style/FileName:
|
18
|
+
Enabled: false
|
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in vagrant-orchestrate.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :development do
|
7
|
+
gem "vagrant", git: "https://github.com/mitchellh/vagrant.git"
|
8
|
+
gem "vagrant-spec", git: "https://github.com/mitchellh/vagrant-spec.git"
|
9
|
+
end
|
10
|
+
|
11
|
+
group :plugins do
|
12
|
+
gem "vagrant-orchestrate", path: "."
|
13
|
+
gem "vagrant-managed-servers"
|
14
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2014 Cimpress
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Vagrant Orchestrate
|
2
|
+
|
3
|
+
This is a Vagrant 1.6+ plugin that allows orchestrated deployments
|
4
|
+
to existing servers on top of the excellent vagrant-managed-servers plugin.
|
5
|
+
It features a powerful templating `init` command and is designed from the
|
6
|
+
ground up to be cross-platform, with first class support for Windows,
|
7
|
+
Linux, and Mac.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
Install using the standard Vagrant plugin installation method:
|
12
|
+
|
13
|
+
$ vagrant plugin install vagrant-orchestrate
|
14
|
+
|
15
|
+
### Initialization
|
16
|
+
Initialize a Vagrantfile to orchestrate running a script on multiple managed servers
|
17
|
+
|
18
|
+
$ vagrant orchestrate init --shell
|
19
|
+
|
20
|
+
You'll need to edit your Vagrantfile and replace some of variables, such as ssh username and
|
21
|
+
password, and the path to the script to run. The first line of the file defines an array of
|
22
|
+
managed servers that the `push` command will operate on.
|
23
|
+
|
24
|
+
This works for Windows managed servers as well
|
25
|
+
|
26
|
+
$ vagrant orchestrate init --winrm [--winrm-username=USERNAME --winrm-password=PASSWORD]
|
27
|
+
|
28
|
+
For a full list of init options, run `vagrant orchestrate init --help`
|
29
|
+
|
30
|
+
### Pushing changes
|
31
|
+
Go ahead and push changes to your managed servers.
|
32
|
+
|
33
|
+
$ vagrant orchestrate push
|
34
|
+
|
35
|
+
You can run vagrant with increased verbosity if you run into problems
|
36
|
+
|
37
|
+
$ vagrant orchestrate push --debug
|
38
|
+
|
39
|
+
## Branching strategy
|
40
|
+
|
41
|
+
If you have several environments (e.g. dev, test, prod), it is recommended to create
|
42
|
+
a separate branch for each environment and put the appropriate servers into the
|
43
|
+
managed_servers array at the top of the Vagrantfile for each. To move a change
|
44
|
+
across branches, simply create a feature branch from your earliest branch and then
|
45
|
+
merge that feature into downstream environments to avoid conflicts.
|
46
|
+
|
47
|
+
## Tips for Windows hosts
|
48
|
+
|
49
|
+
* Need rsync? Install [OpenSSH](http://www.mls-software.com/opensshd.html) and then run this [script]() to install rsync. Vagrant managed servers currently only works with cygwin based rsync implementations.
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
1. Fork it ( https://github.com/chrisbaldauf/vagrant-orchestrate/fork )
|
54
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
55
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
56
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
57
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require "vagrant"
|
3
|
+
|
4
|
+
# rubocop:disable Metrics/ClassLength
|
5
|
+
module VagrantPlugins
|
6
|
+
module Orchestrate
|
7
|
+
module Command
|
8
|
+
class Init < Vagrant.plugin("2", :command)
|
9
|
+
include Vagrant::Util
|
10
|
+
|
11
|
+
DEFAULT_SHELL_PATH = "{{YOUR_SCRIPT_PATH}}"
|
12
|
+
DEFAULT_SHELL_INLINE = "{{YOUR_SCRIPT_COMMAND}}"
|
13
|
+
DEFAULT_WINRM_USERNAME = "{{YOUR_WINRM_USERNAME}}"
|
14
|
+
DEFAULT_WINRM_PASSWORD = "{{YOUR_WINRM_PASSWORD}}"
|
15
|
+
DEFAULT_SSH_USERNAME = "{{YOUR_SSH_USERNAME}}"
|
16
|
+
DEFAULT_SSH_PASSWORD = "{{YOUR_SSH_PASSWORD}}"
|
17
|
+
DEFAULT_SSH_PRIVATE_KEY_PATH = "{{YOUR_SSH_PRIVATE_KEY_PATH}}"
|
18
|
+
DEFAULT_PLUGINS = ["vagrant-managed-servers"]
|
19
|
+
|
20
|
+
# rubocop:disable Metrics/AbcSize, MethodLength
|
21
|
+
def execute
|
22
|
+
options = {}
|
23
|
+
|
24
|
+
options[:provisioners] = []
|
25
|
+
options[:servers] = []
|
26
|
+
options[:plugins] = DEFAULT_PLUGINS
|
27
|
+
|
28
|
+
opts = OptionParser.new do |o|
|
29
|
+
o.banner = "Usage: vagrant orchestrate init [options]"
|
30
|
+
o.separator ""
|
31
|
+
o.separator "Options:"
|
32
|
+
o.separator ""
|
33
|
+
|
34
|
+
o.on("--provision-with x,y,z", Array, "Init only certain provisioners, by type.") do |list|
|
35
|
+
options[:provisioners] = list
|
36
|
+
end
|
37
|
+
|
38
|
+
o.on("--shell", "Shorthand for --provision-with shell") do
|
39
|
+
options[:provisioners] << "shell"
|
40
|
+
end
|
41
|
+
|
42
|
+
o.on("--shell-paths x,y,z", Array,
|
43
|
+
"Comma separated list of shell scripts to run on provision. Only with --shell") do |list|
|
44
|
+
options[:shell_paths] = list
|
45
|
+
end
|
46
|
+
|
47
|
+
o.on("--shell-inline command", String, "Inline script to run. Only with --shell") do |c|
|
48
|
+
options[:shell_inline] = c
|
49
|
+
end
|
50
|
+
|
51
|
+
o.on("--puppet", "Shorthand for --provisioner-with=puppet") do
|
52
|
+
options[:provisioners] << "puppet"
|
53
|
+
end
|
54
|
+
|
55
|
+
o.on("--ssh-username USERNAME", String, "The username for communicating over ssh") do |u|
|
56
|
+
options[:ssh_username] = u
|
57
|
+
end
|
58
|
+
|
59
|
+
o.on("--ssh-password PASSWORD", String, "The username for communicating over ssh") do |p|
|
60
|
+
options[:ssh_password] = p
|
61
|
+
end
|
62
|
+
|
63
|
+
o.on("--ssh-private-key-path PATH", String, "Paths to the private key for communinicating over ssh") do |k|
|
64
|
+
options[:ssh_private_key_path] = k
|
65
|
+
end
|
66
|
+
|
67
|
+
o.on("--winrm", "Use the winrm communicator") do
|
68
|
+
options[:communicator] = "winrm"
|
69
|
+
end
|
70
|
+
|
71
|
+
o.on("--winrm-username USERNAME", String, "The username for communicating with winrm") do |u|
|
72
|
+
options[:winrm_username] = u
|
73
|
+
end
|
74
|
+
|
75
|
+
o.on("--winrm-password PASSWORD", String, "The password for communicating with winrm") do |p|
|
76
|
+
options[:winrm_password] = p
|
77
|
+
end
|
78
|
+
|
79
|
+
o.on("--plugins x,y,z", Array, "A comma separated list of vagrant plugins to be installed") do |p|
|
80
|
+
options[:plugins] += p
|
81
|
+
end
|
82
|
+
|
83
|
+
o.on("--servers x,y,z", Array, "A comma separated list of servers hostnames or IPs to deploy to") do |list|
|
84
|
+
options[:servers] = list
|
85
|
+
end
|
86
|
+
|
87
|
+
o.on("-f", "--force", "Force overwriting of files") do
|
88
|
+
options[:force] = true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
argv = parse_options(opts)
|
93
|
+
return unless argv
|
94
|
+
|
95
|
+
options[:shell_paths] ||= options[:shell_inline] ? [] : [DEFAULT_SHELL_PATH]
|
96
|
+
options[:shell_inline] ||= DEFAULT_SHELL_INLINE
|
97
|
+
options[:winrm_username] ||= DEFAULT_WINRM_USERNAME
|
98
|
+
options[:winrm_password] ||= DEFAULT_WINRM_PASSWORD
|
99
|
+
options[:communicator] ||= "ssh"
|
100
|
+
options[:ssh_username] ||= DEFAULT_SSH_USERNAME
|
101
|
+
options[:ssh_password] ||= DEFAULT_SSH_PASSWORD unless options[:ssh_private_key_path]
|
102
|
+
options[:ssh_private_key_path] ||= DEFAULT_SSH_PRIVATE_KEY_PATH
|
103
|
+
|
104
|
+
contents = TemplateRenderer.render(Orchestrate.source_root.join("templates/vagrant/Vagrantfile"),
|
105
|
+
provisioners: options[:provisioners],
|
106
|
+
shell_paths: options[:shell_paths],
|
107
|
+
shell_inline: options[:shell_inline],
|
108
|
+
communicator: options[:communicator],
|
109
|
+
winrm_username: options[:winrm_username],
|
110
|
+
winrm_password: options[:winrm_password],
|
111
|
+
ssh_username: options[:ssh_username],
|
112
|
+
ssh_password: options[:ssh_password],
|
113
|
+
ssh_private_key_path: options[:ssh_private_key_path],
|
114
|
+
servers: options[:servers],
|
115
|
+
plugins: options[:plugins]
|
116
|
+
)
|
117
|
+
write_vagrantfile(contents, options)
|
118
|
+
|
119
|
+
@env.ui.info(I18n.t("vagrant.commands.init.success"), prefix: false)
|
120
|
+
|
121
|
+
# Success, exit status 0
|
122
|
+
0
|
123
|
+
end
|
124
|
+
# rubocop:enable Metrics/AbcSize, MethodLength
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def write_vagrantfile(contents, options)
|
129
|
+
save_path = Pathname.new("Vagrantfile").expand_path(@env.cwd)
|
130
|
+
save_path.delete if save_path.exist? && options[:force]
|
131
|
+
fail Vagrant::Errors::VagrantfileExistsError if save_path.exist?
|
132
|
+
|
133
|
+
begin
|
134
|
+
save_path.open("w+") do |f|
|
135
|
+
f.write(contents)
|
136
|
+
end
|
137
|
+
rescue Errno::EACCES
|
138
|
+
raise Vagrant::Errors::VagrantfileWriteError
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
# rubocop:enable Metrics/ClassLength
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require "vagrant"
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module Orchestrate
|
6
|
+
module Command
|
7
|
+
class Push < Vagrant.plugin("2", :command)
|
8
|
+
include Vagrant::Util
|
9
|
+
|
10
|
+
def execute
|
11
|
+
options = {}
|
12
|
+
|
13
|
+
opts = OptionParser.new do |o|
|
14
|
+
o.banner = "Usage: vagrant orchestrate push"
|
15
|
+
o.separator ""
|
16
|
+
end
|
17
|
+
|
18
|
+
# Parse the options
|
19
|
+
argv = parse_options(opts)
|
20
|
+
|
21
|
+
with_target_vms(argv, provider: :managed) do |machine|
|
22
|
+
unless machine.name.to_s.start_with? "managed-"
|
23
|
+
@logger.debug("Skipping machine #{machine.name}")
|
24
|
+
next
|
25
|
+
end
|
26
|
+
|
27
|
+
machine.action(:up, options)
|
28
|
+
machine.action(:provision, options)
|
29
|
+
machine.action(:destroy, options)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require "vagrant"
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module Orchestrate
|
6
|
+
module Command
|
7
|
+
class Root < Vagrant.plugin(2, :command)
|
8
|
+
def self.synopsis
|
9
|
+
'Orchestrates provsioning of managed servers. Useful for deploying changes \
|
10
|
+
repeatedly across multiple managed environments'
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(argv, env)
|
14
|
+
super
|
15
|
+
|
16
|
+
@main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
17
|
+
|
18
|
+
@subcommands = Vagrant::Registry.new
|
19
|
+
|
20
|
+
@subcommands.register(:init) do
|
21
|
+
require_relative "init"
|
22
|
+
Init
|
23
|
+
end
|
24
|
+
|
25
|
+
@subcommands.register(:push) do
|
26
|
+
require_relative "push"
|
27
|
+
Push
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def execute
|
32
|
+
if @main_args.include?("-h") || @main_args.include?("--help")
|
33
|
+
# Print the help for all the box commands.
|
34
|
+
return help
|
35
|
+
end
|
36
|
+
|
37
|
+
# If we reached this far then we must have a subcommand. If not,
|
38
|
+
# then we also just print the help and exit.
|
39
|
+
command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
|
40
|
+
return help if !command_class || !@sub_command
|
41
|
+
@logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
|
42
|
+
|
43
|
+
# Initialize and execute the command class
|
44
|
+
command_class.new(@sub_args, @env).execute
|
45
|
+
end
|
46
|
+
|
47
|
+
# Prints the help out for this command
|
48
|
+
# rubocop:disable Metrics/AbcSize
|
49
|
+
def help
|
50
|
+
opts = OptionParser.new do |o|
|
51
|
+
o.banner = "Usage: vagrant orchestrate <subcommand> [<args>]"
|
52
|
+
o.separator ""
|
53
|
+
o.separator "Available subcommands:"
|
54
|
+
|
55
|
+
# Add the available subcommands as separators in order to print them
|
56
|
+
# out as well.
|
57
|
+
keys = []
|
58
|
+
@subcommands.each { |key, _value| keys << key.to_s }
|
59
|
+
|
60
|
+
keys.sort.each do |key|
|
61
|
+
o.separator " #{key}"
|
62
|
+
end
|
63
|
+
|
64
|
+
o.separator ""
|
65
|
+
o.separator "For help on any individual subcommand run `vagrant orchestrate <subcommand> -h`"
|
66
|
+
end
|
67
|
+
|
68
|
+
@env.ui.info(opts.help, prefix: false)
|
69
|
+
end
|
70
|
+
# rubocop:enable Metrics/AbcSize
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
begin
|
2
|
+
require "vagrant"
|
3
|
+
rescue LoadError
|
4
|
+
raise "The Vagrant Orchestrate plugin must be run within Vagrant."
|
5
|
+
end
|
6
|
+
|
7
|
+
# This is a sanity check to make sure no one is attempting to install
|
8
|
+
# this into an early Vagrant version.
|
9
|
+
if Vagrant::VERSION < "1.6.0"
|
10
|
+
fail "The Vagrant Orchestrate plugin is only compatible with Vagrant 1.6+"
|
11
|
+
end
|
12
|
+
|
13
|
+
module VagrantPlugins
|
14
|
+
module Orchestrate
|
15
|
+
class Plugin < Vagrant.plugin("2")
|
16
|
+
name "Orchestrate"
|
17
|
+
description <<-DESC
|
18
|
+
This plugin installs commands that make pushing changes to vagrant-managed-servers easy.
|
19
|
+
DESC
|
20
|
+
|
21
|
+
command(:orchestrate) do
|
22
|
+
require_relative "command/root"
|
23
|
+
Command::Root
|
24
|
+
end
|
25
|
+
|
26
|
+
# This initializes the internationalization strings.
|
27
|
+
def self.setup_i18n
|
28
|
+
I18n.load_path << File.expand_path("locales/en.yml", Orchestrate.source_root)
|
29
|
+
I18n.reload!
|
30
|
+
end
|
31
|
+
|
32
|
+
# This sets up our log level to be whatever VAGRANT_LOG is.
|
33
|
+
def self.setup_logging
|
34
|
+
require "log4r"
|
35
|
+
|
36
|
+
level = nil
|
37
|
+
begin
|
38
|
+
level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase)
|
39
|
+
rescue NameError
|
40
|
+
# This means that the logging constant wasn't found,
|
41
|
+
# which is fine. We just keep `level` as `nil`. But
|
42
|
+
# we tell the user.
|
43
|
+
level = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
# Some constants, such as "true" resolve to booleans, so the
|
47
|
+
# above error checking doesn't catch it. This will check to make
|
48
|
+
# sure that the log level is an integer, as Log4r requires.
|
49
|
+
level = nil unless level.is_a?(Integer)
|
50
|
+
|
51
|
+
# Set the logging level on all "vagrant" namespaced
|
52
|
+
# logs as long as we have a valid level.
|
53
|
+
if level
|
54
|
+
Log4r::Logger.new("vagrant_orchestrate").tap do |logger|
|
55
|
+
logger.outputters = Log4r::Outputter.stderr
|
56
|
+
logger.level = level
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "vagrant-orchestrate/plugin"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Orchestrate
|
5
|
+
# This returns the path to the source of this plugin.
|
6
|
+
#
|
7
|
+
# @return [Pathname]
|
8
|
+
def self.source_root
|
9
|
+
@source_root ||= Pathname.new(File.expand_path("../../", __FILE__))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/locales/en.yml
ADDED
File without changes
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
config.filter_run :focus
|
11
|
+
|
12
|
+
# Run specs in random order to surface order dependencies. If you find an
|
13
|
+
# order dependency and want to debug it, you can fix the order by providing
|
14
|
+
# the seed, which is printed after each run.
|
15
|
+
# --seed 1234
|
16
|
+
config.order = "random"
|
17
|
+
end
|
18
|
+
|
19
|
+
def capture_stdout(&_block)
|
20
|
+
original_stdout = $stdout
|
21
|
+
$stdout = fake = StringIO.new
|
22
|
+
begin
|
23
|
+
yield
|
24
|
+
ensure
|
25
|
+
$stdout = original_stdout
|
26
|
+
end
|
27
|
+
fake.string
|
28
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require "vagrant-orchestrate/command/init"
|
2
|
+
require "vagrant-spec/unit"
|
3
|
+
require "pp"
|
4
|
+
|
5
|
+
describe VagrantPlugins::Orchestrate::Command::Init do
|
6
|
+
include_context "vagrant-unit"
|
7
|
+
|
8
|
+
let(:base_argv) { ["-f"] }
|
9
|
+
let(:argv) { [] }
|
10
|
+
let(:iso_env) do
|
11
|
+
env = isolated_environment
|
12
|
+
# We need to load an empty vagrantfile in order for things to be initialized
|
13
|
+
# properly
|
14
|
+
env.vagrantfile("")
|
15
|
+
env.create_vagrant_env ui_class: ui_class
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:ui_class) { nil }
|
19
|
+
|
20
|
+
subject { described_class.new(base_argv + argv, iso_env) }
|
21
|
+
|
22
|
+
["-h", "--help"].each do |arg|
|
23
|
+
describe "init help message #{arg}" do
|
24
|
+
let(:argv) { ["init", arg] }
|
25
|
+
let(:ui_class) { Vagrant::UI::Basic }
|
26
|
+
it "shows help" do
|
27
|
+
output = capture_stdout { subject.execute }
|
28
|
+
expect(output).to include("Usage: vagrant orchestrate init [options]")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "no parameters" do
|
34
|
+
it "creates basic vagrantfile" do
|
35
|
+
subject.execute
|
36
|
+
expect(Dir.entries(iso_env.cwd)).to include("Vagrantfile")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "shell provisioner" do
|
41
|
+
describe "basic operation" do
|
42
|
+
let(:argv) { ["--shell"] }
|
43
|
+
it "creates a vagrantfile with default shell path" do
|
44
|
+
subject.execute
|
45
|
+
expect(iso_env.vagrantfile.config.vm.provisioners.first.type).to eq(:shell)
|
46
|
+
expect(iso_env.vagrantfile.config.vm.provisioners.first.config.path).to eq(described_class::DEFAULT_SHELL_PATH)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "shell path" do
|
51
|
+
let(:argv) { ["--shell", "--shell-paths", "foo.sh"] }
|
52
|
+
it "creates a vagrantfile with custom shell path" do
|
53
|
+
subject.execute
|
54
|
+
expect(iso_env.vagrantfile.config.vm.provisioners.first.type).to eq(:shell)
|
55
|
+
expect(iso_env.vagrantfile.config.vm.provisioners.first.config.path).to eq("foo.sh")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "shell inline" do
|
60
|
+
let(:argv) { ["--shell", "--shell-inline", "echo Hello, World!"] }
|
61
|
+
it "is passed through" do
|
62
|
+
subject.execute
|
63
|
+
expect(iso_env.vagrantfile.config.vm.provisioners.first.config.inline).to eq("echo Hello, World!")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "multiple shell paths" do
|
68
|
+
let(:argv) { ["--shell", "--shell-paths", "foo.sh,bar.sh"] }
|
69
|
+
it "creates a vagrantfile with custom shell path" do
|
70
|
+
subject.execute
|
71
|
+
expect(iso_env.vagrantfile.config.vm.provisioners.first.type).to eq(:shell)
|
72
|
+
expect(iso_env.vagrantfile.config.vm.provisioners.first.config.path).to eq("foo.sh")
|
73
|
+
expect(iso_env.vagrantfile.config.vm.provisioners[1].config.path).to eq("bar.sh")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "puppet provisioner" do
|
79
|
+
describe "basic operation" do
|
80
|
+
let(:argv) { ["--provision-with", "puppet"] }
|
81
|
+
it "creates a vagrantfile with a puppet provisioner" do
|
82
|
+
subject.execute
|
83
|
+
expect(iso_env.vagrantfile.config.vm.provisioners.first.type).to eq(:puppet)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "shorthand" do
|
88
|
+
let(:argv) { ["--puppet"] }
|
89
|
+
it "creates a vagrantfile with a puppet provisioner" do
|
90
|
+
subject.execute
|
91
|
+
expect(iso_env.vagrantfile.config.vm.provisioners.first.type).to eq(:puppet)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "winrm" do
|
97
|
+
describe "basic" do
|
98
|
+
let(:argv) { ["--winrm"] }
|
99
|
+
it "creates a vagrantfile with the winrm communicator" do
|
100
|
+
subject.execute
|
101
|
+
expect(iso_env.vagrantfile.config.vm.communicator).to eq(:winrm)
|
102
|
+
expect(iso_env.vagrantfile.config.winrm.username).to eq(described_class::DEFAULT_WINRM_USERNAME)
|
103
|
+
expect(iso_env.vagrantfile.config.winrm.password).to eq(described_class::DEFAULT_WINRM_PASSWORD)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "username" do
|
108
|
+
let(:argv) { ["--winrm", "--winrm-username", "WINRM_USERNAME"] }
|
109
|
+
it "is parsed correctly" do
|
110
|
+
subject.execute
|
111
|
+
expect(iso_env.vagrantfile.config.winrm.username).to eq("WINRM_USERNAME")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "password" do
|
116
|
+
let(:argv) { ["--winrm", "--winrm-password", "WINRM_PASSWORD"] }
|
117
|
+
it "is parsed correctly" do
|
118
|
+
subject.execute
|
119
|
+
expect(iso_env.vagrantfile.config.winrm.password).to eq("WINRM_PASSWORD")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "ssh" do
|
125
|
+
describe "default" do
|
126
|
+
it "has default username and password" do
|
127
|
+
subject.execute
|
128
|
+
expect(iso_env.vagrantfile.config.ssh.username).to eq(described_class::DEFAULT_SSH_USERNAME)
|
129
|
+
expect(iso_env.vagrantfile.config.ssh.password).to eq(described_class::DEFAULT_SSH_PASSWORD)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "username" do
|
134
|
+
let(:argv) { ["--ssh-username", "SSH_USERNAME"] }
|
135
|
+
it "is passed through" do
|
136
|
+
subject.execute
|
137
|
+
expect(iso_env.vagrantfile.config.ssh.username).to eq("SSH_USERNAME")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "password" do
|
142
|
+
let(:argv) { ["--ssh-password", "SSH_PASSWORD"] }
|
143
|
+
it "is passed through" do
|
144
|
+
subject.execute
|
145
|
+
expect(iso_env.vagrantfile.config.ssh.password).to eq("SSH_PASSWORD")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "private key path" do
|
150
|
+
let(:argv) { ["--ssh-private-key-path", "SSH_PRIVATE_KEY_PATH"] }
|
151
|
+
it "is passed through" do
|
152
|
+
subject.execute
|
153
|
+
expect(iso_env.vagrantfile.config.ssh.private_key_path.first).to eq("SSH_PRIVATE_KEY_PATH")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "plugins" do
|
159
|
+
describe "default" do
|
160
|
+
it "has default plugins in vagrantfile" do
|
161
|
+
subject.execute
|
162
|
+
# Since the plugin stuff isn't part of the actual Vagrantfile spec, we'll
|
163
|
+
# just peek at the text of the file
|
164
|
+
vagrantfile = File.readlines(File.join(iso_env.cwd, "Vagrantfile")).join
|
165
|
+
expect(vagrantfile).to include("required_plugins = %w( #{described_class::DEFAULT_PLUGINS.join(' ')} )")
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "specified plugins" do
|
170
|
+
let(:argv) { ["--plugins", "plugin1,plugin2"] }
|
171
|
+
it "are required" do
|
172
|
+
subject.execute
|
173
|
+
expected = "required_plugins = %w( #{described_class::DEFAULT_PLUGINS.join(' ')} plugin1 plugin2 )"
|
174
|
+
vagrantfile = File.readlines(File.join(iso_env.cwd, "Vagrantfile")).join
|
175
|
+
expect(vagrantfile).to include(expected)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context "servers" do
|
181
|
+
describe "default" do
|
182
|
+
it "has no servers in vagrantfile" do
|
183
|
+
subject.execute
|
184
|
+
vagrantfile = File.readlines(File.join(iso_env.cwd, "Vagrantfile")).join
|
185
|
+
expect(vagrantfile).to include("managed_servers = %w( )")
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "specified servers" do
|
190
|
+
let(:argv) { ["--servers", "server1,server2"] }
|
191
|
+
it "are required" do
|
192
|
+
subject.execute
|
193
|
+
vagrantfile = File.readlines(File.join(iso_env.cwd, "Vagrantfile")).join
|
194
|
+
expect(vagrantfile).to include("managed_servers = %w( server1 server2 )")
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "vagrant-orchestrate/command/root"
|
2
|
+
require "vagrant-orchestrate/command/init"
|
3
|
+
require "vagrant-spec/unit"
|
4
|
+
|
5
|
+
describe VagrantPlugins::Orchestrate::Command::Root do
|
6
|
+
include_context "vagrant-unit"
|
7
|
+
|
8
|
+
let(:argv) { [] }
|
9
|
+
let(:iso_env) do
|
10
|
+
env = isolated_environment
|
11
|
+
env.vagrantfile("")
|
12
|
+
env.create_vagrant_env ui_class: Vagrant::UI::Basic
|
13
|
+
end
|
14
|
+
|
15
|
+
subject { described_class.new(argv, iso_env) }
|
16
|
+
|
17
|
+
["", "-h", "--help"].each do |arg|
|
18
|
+
describe "root help message #{arg}" do
|
19
|
+
let(:argv) { [arg] }
|
20
|
+
it "shows help" do
|
21
|
+
output = capture_stdout { subject.execute }
|
22
|
+
expect(output).to \
|
23
|
+
include("Usage: vagrant orchestrate <subcommand> [<args>]")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
managed_servers = %w( <% servers.each do |s| -%><%= s %> <% end -%>)
|
2
|
+
|
3
|
+
<% if plugins.any? -%>
|
4
|
+
required_plugins = %w( <% plugins.each do |p| -%><%= p %> <% end -%>)
|
5
|
+
required_plugins.each do |plugin|
|
6
|
+
system "vagrant plugin install #{plugin}" unless Vagrant.has_plugin? plugin
|
7
|
+
end
|
8
|
+
<% end %>
|
9
|
+
Vagrant.configure("2") do |config|
|
10
|
+
<% if provisioners.include? "shell" -%>
|
11
|
+
<% shell_paths.each do |path| -%>
|
12
|
+
config.vm.provision "shell", path: "<%= path %>"
|
13
|
+
<% end -%>
|
14
|
+
<% if shell_inline -%>
|
15
|
+
config.vm.provision "shell", inline: "<%= shell_inline %>"
|
16
|
+
<% end -%>
|
17
|
+
<% end -%>
|
18
|
+
<% if provisioners.include? "puppet" -%>
|
19
|
+
config.vm.provision "puppet" do |puppet|
|
20
|
+
end
|
21
|
+
<% end -%>
|
22
|
+
<% if communicator == "ssh" -%>
|
23
|
+
config.ssh.username = "<%= ssh_username %>"
|
24
|
+
<% if ssh_password -%>
|
25
|
+
config.ssh.password = "<%= ssh_password %>"
|
26
|
+
<% end -%>
|
27
|
+
<% if !ssh_password -%>
|
28
|
+
config.ssh.private_key_path = "<%= ssh_private_key_path %>"
|
29
|
+
<% end -%>
|
30
|
+
<% end -%>
|
31
|
+
<% if communicator == "winrm" -%>
|
32
|
+
config.vm.communicator = "<%= communicator %>"
|
33
|
+
config.winrm.username = "<%= winrm_username %>"
|
34
|
+
config.winrm.password = "<%= winrm_password %>"
|
35
|
+
<% end -%>
|
36
|
+
|
37
|
+
managed_servers.each do |instance|
|
38
|
+
config.vm.define "managed-#{instance}" do |box|
|
39
|
+
box.vm.box = "tknerr/managed-server-dummy"
|
40
|
+
box.vm.provider :managed do |provider|
|
41
|
+
provider.server = instance
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'vagrant-orchestrate/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'vagrant-orchestrate'
|
8
|
+
spec.version = VagrantPlugins::Orchestrate::VERSION
|
9
|
+
spec.authors = ['Christopher Baldauf']
|
10
|
+
spec.email = ['cbaldauf@cimpress.com']
|
11
|
+
spec.summary = 'Vagrant plugin to orchestrate the deployment of managed servers.'
|
12
|
+
spec.homepage = ''
|
13
|
+
spec.license = 'Apache 2.0'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
21
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
22
|
+
spec.add_development_dependency 'rspec'
|
23
|
+
# See Gemfile for additional development dependencies that were not available
|
24
|
+
# on rubygems (or another gem source), but needed to be downloaded from git.
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vagrant-orchestrate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christopher Baldauf
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- cbaldauf@cimpress.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- .rspec
|
64
|
+
- .rubocop.yml
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- lib/vagrant-orchestrate.rb
|
70
|
+
- lib/vagrant-orchestrate/command/init.rb
|
71
|
+
- lib/vagrant-orchestrate/command/push.rb
|
72
|
+
- lib/vagrant-orchestrate/command/root.rb
|
73
|
+
- lib/vagrant-orchestrate/plugin.rb
|
74
|
+
- lib/vagrant-orchestrate/version.rb
|
75
|
+
- locales/en.yml
|
76
|
+
- spec/spec_helper.rb
|
77
|
+
- spec/vagrant-orchestrate/command/init_spec.rb
|
78
|
+
- spec/vagrant-orchestrate/command/root_spec.rb
|
79
|
+
- templates/vagrant/Vagrantfile.erb
|
80
|
+
- vagrant-orchestrate.gemspec
|
81
|
+
homepage: ''
|
82
|
+
licenses:
|
83
|
+
- Apache 2.0
|
84
|
+
metadata: {}
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 2.0.14
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: Vagrant plugin to orchestrate the deployment of managed servers.
|
105
|
+
test_files:
|
106
|
+
- spec/spec_helper.rb
|
107
|
+
- spec/vagrant-orchestrate/command/init_spec.rb
|
108
|
+
- spec/vagrant-orchestrate/command/root_spec.rb
|