vagrant-orchestrate 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|