vagrant-orchestrate 0.4.5 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/Rakefile +13 -0
- data/Vagrantfile +30 -0
- data/acceptance/command/prompt_spec.rb +22 -0
- data/acceptance/command/push_spec.rb +78 -0
- data/acceptance/support-skeletons/basic/Vagrantfile +17 -0
- data/acceptance/support-skeletons/basic/dummy.box +0 -0
- data/acceptance/support-skeletons/prompt/Vagrantfile +16 -0
- data/acceptance/support-skeletons/prompt/dummy.box +0 -0
- data/lib/vagrant-orchestrate/action/setcredentials.rb +21 -40
- data/lib/vagrant-orchestrate/command/push.rb +21 -1
- data/lib/vagrant-orchestrate/plugin.rb +0 -4
- data/lib/vagrant-orchestrate/version.rb +1 -1
- data/spec/vagrant-orchestrate/command/init_spec.rb +0 -1
- data/vagrant-spec.config.rb +4 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d1d37bbcceb73c4aeea0523c3132be46e30a5dd
|
4
|
+
data.tar.gz: 8a2d5192f22543df2a99a31b72bd5fb95037d2e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d09668c2feeef5cafe7fff5885597105f7a1194c1b62ae0c07c0d7958b33abfd8ca201ddd0eee00af4b1713666a71cd88b987d06c6c51f385b0ee62253617ef
|
7
|
+
data.tar.gz: 04d66afcfcb9b2867de6b74b26d8d8b951343fcd16f8c1dc823288ef4d68e5055d8b360e3d15f92641660a188c8e5685967dd0ac94240f710574c3c2c2308d78
|
data/.gitignore
CHANGED
data/Rakefile
CHANGED
@@ -7,3 +7,16 @@ RSpec::Core::RakeTask.new(:spec)
|
|
7
7
|
|
8
8
|
task build: ["rubocop:auto_correct", :spec]
|
9
9
|
task default: :build
|
10
|
+
|
11
|
+
desc "Run acceptance tests with vagrant-spec"
|
12
|
+
task :acceptance do
|
13
|
+
puts "Brining up target servers"
|
14
|
+
# Spinning up local servers here, which the managed provider will connect to
|
15
|
+
# by IP. See the Vagrantfile in the root of the repo for more info.
|
16
|
+
system("vagrant up /local/ --no-provision")
|
17
|
+
# To ensure the ntp sync happens even if the servers are already up
|
18
|
+
system("vagrant provision /local/")
|
19
|
+
system("bundle exec vagrant-spec test --components=orchestrate/push orchestrate/prompt")
|
20
|
+
puts "Destroying target servers"
|
21
|
+
system("vagrant destroy -f /local/")
|
22
|
+
end
|
data/Vagrantfile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
managed_servers = %w( 192.168.10.80 192.168.10.81 192.168.10.82 192.168.10.83)
|
2
|
+
|
3
|
+
Vagrant.configure(2) do |config|
|
4
|
+
# These boxes are defined locally to enable acceptance testing. Spinning up
|
5
|
+
# real boxes in the vagrant-spec environment was expensive because it ignored
|
6
|
+
# the cache and didn't expose a facility to view the vagrant output as it ran.
|
7
|
+
# These machines get spun up in the rake task and then the vagrant-spec tests
|
8
|
+
# connect to them by IP address.
|
9
|
+
managed_servers.each_with_index do |ip, index|
|
10
|
+
config.vm.define "local-#{index + 1}" do |ubuntu|
|
11
|
+
# minimize clock skew, since we're using the `date` command to measure
|
12
|
+
# clock skew.
|
13
|
+
ubuntu.vm.provision :shell, inline: "ntpdate pool.ntp.org"
|
14
|
+
ubuntu.vm.box = "ubuntu/trusty64"
|
15
|
+
ubuntu.vm.network "private_network", ip: ip
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# These managed boxes connect to the local boxes defined above by ip address.
|
20
|
+
managed_servers.each_with_index do |server, index|
|
21
|
+
config.vm.define "managed-#{index + 1}" do |managed|
|
22
|
+
managed.vm.box = "managed-server-dummy"
|
23
|
+
managed.vm.box_url = "./dummy.box"
|
24
|
+
managed.ssh.password = "vagrant"
|
25
|
+
managed.vm.provider :managed do |provider|
|
26
|
+
provider.server = server
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "vagrant-spec"
|
2
|
+
|
3
|
+
describe "vagrant orchestrate prompt", component: "orchestrate/prompt" do
|
4
|
+
include_context "acceptance"
|
5
|
+
|
6
|
+
before do
|
7
|
+
environment.skeleton("prompt")
|
8
|
+
end
|
9
|
+
|
10
|
+
# Vagrant throws with the error message below if a prompt is encountered. We need
|
11
|
+
# to make sure that non-push commands don't prompt
|
12
|
+
# Vagrant is attempting to interface with the UI in a way that requires
|
13
|
+
# a TTY. Most actions in Vagrant that require a TTY have configuration
|
14
|
+
# switches to disable this requirement. Please do that or run Vagrant
|
15
|
+
# with TTY.
|
16
|
+
it "doesn't prompt with non-push commands" do
|
17
|
+
assert_execute("vagrant", "status")
|
18
|
+
end
|
19
|
+
|
20
|
+
# TODO: I wish there was a way to simulate prompting, but for now, that is left
|
21
|
+
# to the user as a manual exercise.
|
22
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "vagrant-spec"
|
2
|
+
|
3
|
+
describe "vagrant orchestrate push", component: "orchestrate/push" do
|
4
|
+
include_context "acceptance"
|
5
|
+
|
6
|
+
before do
|
7
|
+
environment.skeleton("basic")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "can push to a set of managed servers" do
|
11
|
+
assert_execute("vagrant", "orchestrate", "push")
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "strategies" do
|
15
|
+
it "can push in parallel" do
|
16
|
+
assert_execute("vagrant", "orchestrate", "push", "--strategy", "parallel")
|
17
|
+
|
18
|
+
machine_names = (1..4).collect { |i| "managed-#{i}" }
|
19
|
+
datetimes = get_sync_times(machine_names)
|
20
|
+
execute("vagrant", "destroy", "-f")
|
21
|
+
|
22
|
+
# Parallel provisioning should happen within a few seconds.
|
23
|
+
ensure_datetimes_within(datetimes, 5)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can push with carary strategy" do
|
27
|
+
assert_execute("vagrant", "orchestrate", "push", "--strategy", "canary", "-f")
|
28
|
+
canary = get_sync_times(["managed-1"]).first
|
29
|
+
the_rest = get_sync_times((2..4).collect { |i| "managed-#{i}" })
|
30
|
+
execute("vagrant", "destroy", "-f")
|
31
|
+
ensure_datetimes_within(the_rest, 5)
|
32
|
+
expect(diff_seconds(canary, the_rest.min)).to be >= 3
|
33
|
+
end
|
34
|
+
|
35
|
+
it "can push with half_half strategy" do
|
36
|
+
assert_execute("vagrant", "orchestrate", "push", "--strategy", "half_half", "-f")
|
37
|
+
first_half = get_sync_times(["managed-1", "managed-2"])
|
38
|
+
second_half = get_sync_times(["managed-3", "managed-4"])
|
39
|
+
execute("vagrant", "destroy", "-f")
|
40
|
+
ensure_datetimes_within(first_half, 5)
|
41
|
+
ensure_datetimes_within(second_half, 5)
|
42
|
+
expect(diff_seconds(first_half.max, second_half.min)).to be >= 3
|
43
|
+
end
|
44
|
+
|
45
|
+
it "can push with carary_half_half strategy" do
|
46
|
+
assert_execute("vagrant", "orchestrate", "push", "--strategy", "canary_half_half", "-f")
|
47
|
+
canary = get_sync_times(["managed-1"]).first
|
48
|
+
first_half = get_sync_times(["managed-2"])
|
49
|
+
second_half = get_sync_times(["managed-3", "managed-4"])
|
50
|
+
execute("vagrant", "destroy", "-f")
|
51
|
+
ensure_datetimes_within(first_half, 5)
|
52
|
+
expect(diff_seconds(canary, first_half.min)).to be > 3
|
53
|
+
expect(diff_seconds(first_half.max, second_half.min)).to be >= 3
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_sync_times(machines)
|
58
|
+
datetimes = []
|
59
|
+
machines.each do |machine|
|
60
|
+
execute("vagrant", "up", machine)
|
61
|
+
# This file is written by the shell provisioner in ../support-skeletons/basic/Vagrantfile
|
62
|
+
result = execute("vagrant", "ssh", "-c", "cat /tmp/sync_time", machine)
|
63
|
+
datetimes << DateTime.parse(result.stdout.chomp)
|
64
|
+
end
|
65
|
+
datetimes
|
66
|
+
end
|
67
|
+
|
68
|
+
# Ensure that the range (max - min) of the datetime objects passed in are within
|
69
|
+
# the given number of seconds.
|
70
|
+
def ensure_datetimes_within(datetimes, seconds)
|
71
|
+
expect(diff_seconds(datetimes.min, datetimes.max)).to be < seconds
|
72
|
+
end
|
73
|
+
|
74
|
+
# The difference between two datetimes in seconds
|
75
|
+
def diff_seconds(start, finish)
|
76
|
+
((finish - start) * 86_400).to_i
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
managed_servers = %w( 192.168.10.80 192.168.10.81 192.168.10.82 192.168.10.83)
|
2
|
+
|
3
|
+
Vagrant.configure(2) do |config|
|
4
|
+
config.ssh.password = "vagrant"
|
5
|
+
managed_servers.each_with_index do |server, index|
|
6
|
+
config.vm.define "managed-#{index + 1}" do |managed|
|
7
|
+
managed.vm.provision "shell", inline: "date > /tmp/sync_time; sleep 3"
|
8
|
+
managed.vm.box = "managed-server-dummy"
|
9
|
+
managed.vm.box_url = "./dummy.box"
|
10
|
+
# TODO: Why in the world do I need this? I thought it was the default!
|
11
|
+
managed.ssh.password = "vagrant"
|
12
|
+
managed.vm.provider :managed do |provider|
|
13
|
+
provider.server = server
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
Binary file
|
@@ -0,0 +1,16 @@
|
|
1
|
+
managed_servers = %w( 192.168.10.80 192.168.10.81 192.168.10.82 192.168.10.83 )
|
2
|
+
|
3
|
+
Vagrant.configure(2) do |config|
|
4
|
+
config.orchestrate.credentials.prompt = true
|
5
|
+
|
6
|
+
managed_servers.each_with_index do |server, index|
|
7
|
+
config.vm.define "managed-#{index + 1}" do |managed|
|
8
|
+
managed.vm.provision "shell", inline: "echo 'hello world'"
|
9
|
+
managed.vm.box = "managed-server-dummy"
|
10
|
+
managed.vm.box_url = "./dummy.box"
|
11
|
+
managed.vm.provider :managed do |provider|
|
12
|
+
provider.server = server
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
Binary file
|
@@ -2,84 +2,65 @@ module VagrantPlugins
|
|
2
2
|
module Orchestrate
|
3
3
|
module Action
|
4
4
|
class SetCredentials
|
5
|
-
def
|
6
|
-
|
7
|
-
end
|
8
|
-
|
9
|
-
# rubocop:disable Metrics/AbcSize
|
10
|
-
def call(env)
|
11
|
-
@machine = env[:machine]
|
12
|
-
|
13
|
-
if @machine.config.orchestrate.credentials
|
14
|
-
@ui = env[:ui]
|
15
|
-
config_creds = @machine.config.orchestrate.credentials
|
16
|
-
(username, password) = retrieve_creds(config_creds)
|
17
|
-
|
18
|
-
# Apply the credentials to the machine info, or back out if we were unable to procure them.
|
19
|
-
if username && password
|
20
|
-
apply_creds(username, password)
|
21
|
-
else
|
22
|
-
@ui.warn <<-WARNING
|
23
|
-
Vagrant-orchestrate could not gather credentials for machine #{@machine.name}. \
|
24
|
-
Continuing with default credentials."
|
25
|
-
WARNING
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
@app.call env
|
30
|
-
end
|
5
|
+
def retrieve_creds(config_creds, ui)
|
6
|
+
return unless config_creds
|
31
7
|
|
32
|
-
def retrieve_creds(config_creds)
|
33
8
|
# Use environment variable overrides, or else what was provided in the config file
|
34
9
|
config_creds.username = ENV["VAGRANT_ORCHESTRATE_USERNAME"] || config_creds.username
|
35
10
|
config_creds.password = ENV["VAGRANT_ORCHESTRATE_PASSWORD"] || config_creds.password
|
36
11
|
|
37
12
|
# Use credentials file to any username or password that is still undiscovered
|
38
|
-
check_creds_file(config_creds) unless config_creds.username && config_creds.password
|
13
|
+
check_creds_file(config_creds, ui) unless config_creds.username && config_creds.password
|
39
14
|
|
15
|
+
config_creds = maybe_prompt(config_creds)
|
16
|
+
|
17
|
+
[config_creds.username, config_creds.password]
|
18
|
+
end
|
19
|
+
|
20
|
+
def maybe_prompt(config_creds)
|
40
21
|
# Only prompt if allowed by config
|
41
22
|
if config_creds.prompt
|
42
|
-
config_creds.username ||= prompt_username
|
43
|
-
config_creds.password ||= prompt_password
|
23
|
+
config_creds.username ||= prompt_username(ui)
|
24
|
+
config_creds.password ||= prompt_password(ui)
|
44
25
|
end
|
45
|
-
|
46
|
-
[config_creds.username, config_creds.password]
|
26
|
+
config_creds
|
47
27
|
end
|
48
28
|
|
49
|
-
def apply_creds(username, password)
|
50
|
-
[
|
29
|
+
def apply_creds(machine, username, password)
|
30
|
+
[machine.config.winrm, machine.config.ssh].each do |config|
|
51
31
|
next unless config
|
52
32
|
config.username = username
|
53
33
|
config.password = password
|
54
34
|
end
|
55
35
|
end
|
56
36
|
|
57
|
-
def prompt_username
|
37
|
+
def prompt_username(ui)
|
58
38
|
default = ENV["USERNAME"]
|
59
39
|
default ||= ENV["USER"]
|
60
40
|
default = ENV["USERDOMAIN"] + "\\" + default if ENV["USERDOMAIN"]
|
61
|
-
username =
|
41
|
+
username = ui.ask("username? [#{default}] ")
|
62
42
|
username = default if username.empty?
|
63
43
|
username
|
64
44
|
end
|
65
45
|
|
66
|
-
def prompt_password
|
67
|
-
|
46
|
+
def prompt_password(ui)
|
47
|
+
ui.ask("password? ", echo: false)
|
68
48
|
end
|
69
49
|
|
70
|
-
def check_creds_file(config_creds)
|
50
|
+
def check_creds_file(config_creds, ui)
|
71
51
|
file_path = config_creds.file_path
|
72
52
|
return unless file_path
|
73
53
|
unless File.exist?(file_path)
|
74
54
|
@ui.info "Credential file not found at #{file_path}. Prompting user for credentials."
|
75
55
|
return
|
76
56
|
end
|
57
|
+
|
77
58
|
begin
|
78
59
|
creds_yaml = YAML.load(File.read(file_path))
|
79
60
|
config_creds.password ||= creds_yaml[:password] || creds_yaml["password"]
|
80
61
|
config_creds.username ||= creds_yaml[:username] || creds_yaml["username"]
|
81
62
|
rescue
|
82
|
-
|
63
|
+
ui.warn "Credentials file at #{file_path} was not valid YAML. Prompting user for credentials."
|
83
64
|
end
|
84
65
|
end
|
85
66
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "optparse"
|
2
2
|
require "vagrant"
|
3
|
+
require "vagrant-orchestrate/action/setcredentials"
|
3
4
|
|
4
5
|
# Borrowed from http://stackoverflow.com/questions/12374645/splitting-an-array-into-equal-parts-in-ruby
|
5
6
|
class Array
|
@@ -57,6 +58,8 @@ module VagrantPlugins
|
|
57
58
|
return 0
|
58
59
|
end
|
59
60
|
|
61
|
+
retrieve_creds(machines) if @env.vagrantfile.config.orchestrate.credentials
|
62
|
+
|
60
63
|
options[:parallel] = true
|
61
64
|
strategy = options[:strategy] || @env.vagrantfile.config.orchestrate.strategy
|
62
65
|
@env.ui.info("Pushing to managed servers using #{strategy} strategy.")
|
@@ -130,7 +133,7 @@ module VagrantPlugins
|
|
130
133
|
# rubocop:enable Metrics/AbcSize, MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
131
134
|
|
132
135
|
def prompt_for_continue
|
133
|
-
result = @env.ui.ask("Deployment paused for manual review. Would you like to continue? (y/n)")
|
136
|
+
result = @env.ui.ask("Deployment paused for manual review. Would you like to continue? (y/n) ")
|
134
137
|
if result.upcase != "Y"
|
135
138
|
@env.ui.info("Deployment push action cancelled by user")
|
136
139
|
return false
|
@@ -145,6 +148,23 @@ module VagrantPlugins
|
|
145
148
|
end
|
146
149
|
end
|
147
150
|
end
|
151
|
+
|
152
|
+
def retrieve_creds(machines)
|
153
|
+
creds = VagrantPlugins::Orchestrate::Action::SetCredentials.new
|
154
|
+
(username, password) = creds.retrieve_creds(@env.vagrantfile.config.orchestrate.credentials, @env.ui)
|
155
|
+
|
156
|
+
# Apply the credentials to the machine info, or back out if we were unable to procure them.
|
157
|
+
if username && password
|
158
|
+
machines.each do |machine|
|
159
|
+
creds.apply_creds(machine, username, password)
|
160
|
+
end
|
161
|
+
else
|
162
|
+
@env.ui.warn <<-WARNING
|
163
|
+
Vagrant-orchestrate could not gather credentials. \
|
164
|
+
Continuing with default credentials."
|
165
|
+
WARNING
|
166
|
+
end
|
167
|
+
end
|
148
168
|
end
|
149
169
|
end
|
150
170
|
end
|
@@ -34,10 +34,6 @@ module VagrantPlugins
|
|
34
34
|
Command::Root
|
35
35
|
end
|
36
36
|
|
37
|
-
action_hook(:orchestrate, Plugin::ALL_ACTIONS) do |hook|
|
38
|
-
hook.before Vagrant::Action::Builtin::ConfigValidate, Action::SetCredentials
|
39
|
-
end
|
40
|
-
|
41
37
|
action_hook(:orchestrate, :machine_action_up) do |hook|
|
42
38
|
hook.prepend Action::FilterManaged
|
43
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vagrant-orchestrate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Baldauf
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -81,6 +81,13 @@ files:
|
|
81
81
|
- LICENSE
|
82
82
|
- README.md
|
83
83
|
- Rakefile
|
84
|
+
- Vagrantfile
|
85
|
+
- acceptance/command/prompt_spec.rb
|
86
|
+
- acceptance/command/push_spec.rb
|
87
|
+
- acceptance/support-skeletons/basic/Vagrantfile
|
88
|
+
- acceptance/support-skeletons/basic/dummy.box
|
89
|
+
- acceptance/support-skeletons/prompt/Vagrantfile
|
90
|
+
- acceptance/support-skeletons/prompt/dummy.box
|
84
91
|
- docs/strategy.md
|
85
92
|
- dummy.box
|
86
93
|
- lib/vagrant-orchestrate.rb
|
@@ -103,6 +110,7 @@ files:
|
|
103
110
|
- templates/vagrant/Vagrantfile.erb
|
104
111
|
- templates/vagrant/dummy.box
|
105
112
|
- vagrant-orchestrate.gemspec
|
113
|
+
- vagrant-spec.config.rb
|
106
114
|
homepage: https://github.com/Cimpress-MCP/vagrant-orchestrate
|
107
115
|
licenses:
|
108
116
|
- Apache 2.0
|