vagrant-orchestrate 0.4.5 → 0.4.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4760cd6a2cdc63739d752fe2341dd49e2e174676
4
- data.tar.gz: c244aaadc7615858ae95ee9315ae6d306cdad82e
3
+ metadata.gz: 2d1d37bbcceb73c4aeea0523c3132be46e30a5dd
4
+ data.tar.gz: 8a2d5192f22543df2a99a31b72bd5fb95037d2e4
5
5
  SHA512:
6
- metadata.gz: bbabd2ed817ea80ce81706464852f569b59e5e5bae90b25979765380772af47857c94f61e212dcd4776eed92cfe820e44811e92e63c9ba705bc89eaf6d12cb07
7
- data.tar.gz: a7f8b8f32cc8d86ba46267ab946a1bdc730e0a309fcdac9288c2bde3978d2477fbf7a57c3aec28f0922f36dea73697678b1a46076276b885ccb6f054e14c2993
6
+ metadata.gz: 4d09668c2feeef5cafe7fff5885597105f7a1194c1b62ae0c07c0d7958b33abfd8ca201ddd0eee00af4b1713666a71cd88b987d06c6c51f385b0ee62253617ef
7
+ data.tar.gz: 04d66afcfcb9b2867de6b74b26d8d8b951343fcd16f8c1dc823288ef4d68e5055d8b360e3d15f92641660a188c8e5685967dd0ac94240f710574c3c2c2308d78
data/.gitignore CHANGED
@@ -14,6 +14,5 @@
14
14
  mkmf.log
15
15
 
16
16
  /.vagrant/
17
- Vagrantfile
18
17
  .DS_Store
19
18
  servers.json
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
@@ -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
@@ -2,84 +2,65 @@ module VagrantPlugins
2
2
  module Orchestrate
3
3
  module Action
4
4
  class SetCredentials
5
- def initialize(app, _env)
6
- @app = app
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
- [@machine.config.winrm, @machine.config.ssh].each do |config|
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 = @ui.ask("username? [#{default}] ")
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
- @ui.ask("password? ", echo: false)
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
- @ui.warn "Credentials file at #{file_path} was not valid YAML. Prompting user for credentials."
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
@@ -1,5 +1,5 @@
1
1
  module VagrantPlugins
2
2
  module Orchestrate
3
- VERSION = "0.4.5"
3
+ VERSION = "0.4.6"
4
4
  end
5
5
  end
@@ -1,6 +1,5 @@
1
1
  require "vagrant-orchestrate/command/init"
2
2
  require "vagrant-spec/unit"
3
- require "pp"
4
3
 
5
4
  describe VagrantPlugins::Orchestrate::Command::Init do
6
5
  include_context "vagrant-unit"
@@ -0,0 +1,4 @@
1
+ Vagrant::Spec::Acceptance.configure do |c|
2
+ c.component_paths << File.join("acceptance")
3
+ c.skeleton_paths << File.join("acceptance", "support-skeletons")
4
+ 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.5
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-02 00:00:00.000000000 Z
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