vagrant-orchestrate 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +38 -4
- data/Rakefile +1 -0
- data/docs/strategy.md +91 -0
- data/lib/vagrant-orchestrate/action/setcredentials.rb +88 -0
- data/lib/vagrant-orchestrate/command/init.rb +15 -5
- data/lib/vagrant-orchestrate/command/push.rb +101 -13
- data/lib/vagrant-orchestrate/command/root.rb +1 -2
- data/lib/vagrant-orchestrate/config.rb +76 -0
- data/lib/vagrant-orchestrate/plugin.rb +5 -0
- data/lib/vagrant-orchestrate/version.rb +1 -1
- data/templates/vagrant/Vagrantfile.erb +6 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc2a1392e8001d976648512c3639ccf0bfa02422
|
4
|
+
data.tar.gz: d2fca53a34f4ebbb9353d5bcf084034cff22f47f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e432897d4477f5907b39f65ed709899a194cc5a537c808ca83cf15ee6206a6c8f5118b059c2ab673ebce14fce864979fb75dee4d4b2bc947232fec7934fffcb0
|
7
|
+
data.tar.gz: e010c6132a1ee981a681228c111edae7b0318d52d17d059b9744a251257e13093a708ce309c375f5d31f9e0ccc8b81df51c3843ddc716f37bec315d22ff568a5
|
data/README.md
CHANGED
@@ -192,6 +192,34 @@ Current machine states:
|
|
192
192
|
|
193
193
|
local not created (virtualbox)
|
194
194
|
```
|
195
|
+
|
196
|
+
#### Credentials
|
197
|
+
|
198
|
+
Vagrant orchestrate offers the capability to prompt for credentials from the command
|
199
|
+
line at the time of a push. You can initialize your Vagrantfile to declare this
|
200
|
+
by passing the `--credentials-prompt` flag to the `vagrant orchestrate init` command,
|
201
|
+
or add the following to your Vagrantfile.
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
Vagrant.configure("2") do |config|
|
205
|
+
|
206
|
+
...
|
207
|
+
|
208
|
+
config.orchestrate.credentials do |creds|
|
209
|
+
creds.prompt = true
|
210
|
+
end
|
211
|
+
```
|
212
|
+
|
213
|
+
The credentials config object can accept one additional parameter, `file_path`. Setting
|
214
|
+
`creds.file_path = path/to/username_password.yaml` tells vagrant-orchestrate to
|
215
|
+
look for a file at the given path, and read from its :username and :password fields
|
216
|
+
('username' and 'password' are also accepted). Additionally, you can pass the username
|
217
|
+
and password in using the `VAGRANT_ORCHESTRATE_USERNAME` and `VAGRANT_ORCHESTRATE_PASSWORD`
|
218
|
+
environment variables. Environment variables take precedence over the file, and the file
|
219
|
+
takes precedence over the prompting. It is possible to set `prompt` to `false`, or leave
|
220
|
+
it unset, in which case only environment variables and the credentials file (if provided)
|
221
|
+
will be checked.
|
222
|
+
|
195
223
|
#### Puppet
|
196
224
|
|
197
225
|
Experimental puppet templating support is available as well with the `--puppet` flag and associated options
|
@@ -226,15 +254,20 @@ modules/
|
|
226
254
|
For a full list of init options, run `vagrant orchestrate init --help`
|
227
255
|
|
228
256
|
### Pushing changes
|
229
|
-
Go ahead and push changes to your managed servers,
|
257
|
+
Go ahead and push changes to your managed servers, in serial by default.
|
230
258
|
|
231
259
|
$ vagrant orchestrate push
|
232
260
|
|
233
|
-
The push command is currently limited by convention to vagrant machines that
|
261
|
+
The push command is currently limited by convention to vagrant machines that use the `:managed` provider. So if you have other, local machines defined in the Vagrantfile, `vagrant orchestrate push` will not operate on those.
|
262
|
+
|
263
|
+
#### Deployment Strategy
|
264
|
+
|
265
|
+
Vagrant Orchestrate supports several deployment [strategies](docs/strategies.md), including parallel and
|
266
|
+
blue-green.
|
234
267
|
|
235
|
-
You can
|
268
|
+
You can push changes to all of your servers in parallel with
|
236
269
|
|
237
|
-
$ vagrant orchestrate push --
|
270
|
+
$ vagrant orchestrate push --strategy parallel
|
238
271
|
|
239
272
|
## Filtering managed commands
|
240
273
|
It can be easy to make mistakes such as rebooting production if you have managed long-lived servers as well as local VMs defined in your Vagrantfile. We add some protection with the `orchestrate.filter_managed_commands` configuration setting, which will cause up, provision, reload, and destroy commands to be ignored for servers with the managed provider.
|
@@ -254,6 +287,7 @@ merge that feature into downstream environments to avoid conflicts.
|
|
254
287
|
## Tips for Windows hosts
|
255
288
|
|
256
289
|
* Need rsync? Install [OpenSSH](http://www.mls-software.com/opensshd.html) and then run this [script](https://github.com/joefitzgerald/packer-windows/blob/master/scripts/rsync.bat) to install rsync. Vagrant managed servers currently only works with cygwin based rsync implementations.
|
290
|
+
* If you're using winrm-s as your communicator, you'll need to configure it first on the target machine! Check out [the plugin readme](https://github.com/Cimpress-MCP/vagrant-winrm-s/blob/master/README.md#setting-up-your-server) for instructions on how to set this up.
|
257
291
|
|
258
292
|
## Contributing
|
259
293
|
|
data/Rakefile
CHANGED
data/docs/strategy.md
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# Deployment Strategies
|
2
|
+
|
3
|
+
Vagrant Orchestrate supports several deployment strategies, including parallel and
|
4
|
+
blue-green. Here we'll cover how to use the various strategies as well as describing
|
5
|
+
situations when each might be useful.
|
6
|
+
|
7
|
+
## Specifying a strategy
|
8
|
+
|
9
|
+
### Command line
|
10
|
+
|
11
|
+
Strategies can be passed on the command line with the `--strategy` parameter
|
12
|
+
|
13
|
+
$ vagrant orchestrate push --strategy parallel
|
14
|
+
|
15
|
+
### Vagrantfile configuration
|
16
|
+
|
17
|
+
Alternatively, you can specify the deployment strategy in your Vagrantfile
|
18
|
+
|
19
|
+
config.orchestrate.strategy = :parallel
|
20
|
+
|
21
|
+
Command line parameters take precedence over Vagrantfile set configuration values.
|
22
|
+
|
23
|
+
## Strategies
|
24
|
+
|
25
|
+
### Serial (default)
|
26
|
+
This will deploy to the target servers one at a time. This can be useful if you
|
27
|
+
have a small number servers, or if you need to keep the majority of your servers
|
28
|
+
online in order to support your application's load.
|
29
|
+
|
30
|
+
$ vagrant orchestrate push --strategy serial
|
31
|
+
|
32
|
+
config.orchestrate.strategy = :serial
|
33
|
+
|
34
|
+
|
35
|
+
### Parallel
|
36
|
+
This strategy will deploy to all of the target servers at the same time. This is
|
37
|
+
useful if you want to minimize the amount of time that an overall deployment takes.
|
38
|
+
Depending on how you've written your provisioners, this could cause downtime for
|
39
|
+
the application that is being deployed.
|
40
|
+
|
41
|
+
$ vagrant orchestrate push --strategy parallel
|
42
|
+
|
43
|
+
config.orchestrate.strategy = :parallel
|
44
|
+
|
45
|
+
### Canary
|
46
|
+
The canary strategy will deploy to a single server, provide an opportunity to
|
47
|
+
test the deployed server, and then deploy the remainder of the servers in parallel.
|
48
|
+
This is a great opportunity to test one node of your cluster before blasting your
|
49
|
+
changes out to them all. This can be particularly useful when combined with post
|
50
|
+
provision [trigger](https://github.com/emyl/vagrant-triggers) to run a smoke test.
|
51
|
+
|
52
|
+
$ vagrant orchestrate push --strategy canary
|
53
|
+
|
54
|
+
config.orchestrate.strategy = :canary
|
55
|
+
|
56
|
+
### Blue Green
|
57
|
+
The [Blue Green](http://martinfowler.com/bliki/BlueGreenDeployment.html) deployment
|
58
|
+
strategy deploys to half of the cluster in parallel, then the other half, with
|
59
|
+
a pause in between. This doesn't manage any of your load balancing or networking
|
60
|
+
configuraiton for you, but if your application has a healthcheck that your load
|
61
|
+
balancer respects, it should be easy to turn it off at the start of your provisioning
|
62
|
+
and back on at the end. If your application can serve the load on half of its nodes
|
63
|
+
then this will be the best blend of getting the deployment done quickly and maintaining
|
64
|
+
a working application.
|
65
|
+
|
66
|
+
$ vagrant orchestrate push --strategy blue_green
|
67
|
+
|
68
|
+
config.orchestrate.strategy = :blue_green
|
69
|
+
|
70
|
+
### Canary Blue Green
|
71
|
+
This strategy simply combines the two immediately above - deploying to a single
|
72
|
+
server, pausing, then to half the cluster in parallel, pausing, and then the remainder,
|
73
|
+
also in parallel. Good if you have a large number of servers and want to do a
|
74
|
+
smoke test of a single server before committing to pushing to half of your farm.
|
75
|
+
|
76
|
+
$ vagrant orchestrate push --strategy canary_blue_green
|
77
|
+
|
78
|
+
config.orchestrate.strategy = :canary_blue_green
|
79
|
+
|
80
|
+
## Suppressing Prompts
|
81
|
+
In order to automate the deployment process, it can be very useful to suppress
|
82
|
+
prompts. You can achieve that in two ways:
|
83
|
+
|
84
|
+
From the command line, add the `--force` or `-f` parameter
|
85
|
+
|
86
|
+
$ vagrant orchestrate push --strategy canary -f
|
87
|
+
|
88
|
+
|
89
|
+
Within your vagrantfile, set the `force_push` setting to true
|
90
|
+
|
91
|
+
config.orchestrate.force_push = true
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Orchestrate
|
3
|
+
module Action
|
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
|
31
|
+
|
32
|
+
def retrieve_creds(config_creds)
|
33
|
+
# Use environment variable overrides, or else what was provided in the config file
|
34
|
+
config_creds.username = ENV["VAGRANT_ORCHESTRATE_USERNAME"] || config_creds.username
|
35
|
+
config_creds.password = ENV["VAGRANT_ORCHESTRATE_PASSWORD"] || config_creds.password
|
36
|
+
|
37
|
+
# 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
|
39
|
+
|
40
|
+
# Only prompt if allowed by config
|
41
|
+
if config_creds.prompt
|
42
|
+
config_creds.username ||= prompt_username
|
43
|
+
config_creds.password ||= prompt_password
|
44
|
+
end
|
45
|
+
|
46
|
+
[config_creds.username, config_creds.password]
|
47
|
+
end
|
48
|
+
|
49
|
+
def apply_creds(username, password)
|
50
|
+
configs = [@machine.config.winrm, @machine.config.ssh]
|
51
|
+
configs.each do |config|
|
52
|
+
next unless config
|
53
|
+
config.username = username
|
54
|
+
config.password = password
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def prompt_username
|
59
|
+
default = ENV["USERNAME"]
|
60
|
+
default ||= ENV["USER"]
|
61
|
+
username = @ui.ask("username? [#{default}]")
|
62
|
+
username = default if username.empty?
|
63
|
+
username
|
64
|
+
end
|
65
|
+
|
66
|
+
def prompt_password
|
67
|
+
@ui.ask("password?", echo: false)
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_creds_file(config_creds)
|
71
|
+
file_path = config_creds.file_path
|
72
|
+
return unless file_path
|
73
|
+
unless File.exist?(file_path)
|
74
|
+
@ui.info "Credential file not found at #{file_path}. Prompting user for credentials."
|
75
|
+
return
|
76
|
+
end
|
77
|
+
begin
|
78
|
+
creds_yaml = YAML.load(File.read(file_path))
|
79
|
+
config_creds.password ||= creds_yaml[:password] || creds_yaml["password"]
|
80
|
+
config_creds.username ||= creds_yaml[:username] || creds_yaml["username"]
|
81
|
+
rescue
|
82
|
+
@ui.warn "Credentials file at #{file_path} was not valid YAML. Prompting user for credentials."
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -41,7 +41,7 @@ module VagrantPlugins
|
|
41
41
|
end
|
42
42
|
|
43
43
|
o.on("--shell-paths x,y,z", Array,
|
44
|
-
"Comma
|
44
|
+
"Comma-separated list of shell scripts to run on provision. Only with --shell") do |list|
|
45
45
|
options[:shell_paths] = list
|
46
46
|
end
|
47
47
|
|
@@ -66,7 +66,7 @@ module VagrantPlugins
|
|
66
66
|
options[:ssh_username] = u
|
67
67
|
end
|
68
68
|
|
69
|
-
o.on("--ssh-password PASSWORD", String, "The
|
69
|
+
o.on("--ssh-password PASSWORD", String, "The password for communicating over ssh") do |p|
|
70
70
|
options[:ssh_password] = p
|
71
71
|
end
|
72
72
|
|
@@ -102,6 +102,15 @@ module VagrantPlugins
|
|
102
102
|
o.on("-f", "--force", "Force overwriting of files") do
|
103
103
|
options[:force] = true
|
104
104
|
end
|
105
|
+
|
106
|
+
o.on("--credentials-prompt", "Prompt for credentials when performing orchestrate operations") do
|
107
|
+
options[:creds_prompt] = true
|
108
|
+
end
|
109
|
+
|
110
|
+
cfpmsg = "The path to a yaml file containing :username and :password fields to use with vagrant orchestrate"
|
111
|
+
o.on("--credentials-file-path FILEPATH", String, cfpmsg) do |file_path|
|
112
|
+
options[:creds_file_path] = file_path
|
113
|
+
end
|
105
114
|
end
|
106
115
|
|
107
116
|
argv = parse_options(opts)
|
@@ -131,7 +140,8 @@ module VagrantPlugins
|
|
131
140
|
ssh_private_key_path: options[:ssh_private_key_path],
|
132
141
|
servers: options[:servers],
|
133
142
|
environments: options[:environments],
|
134
|
-
plugins: options[:plugins]
|
143
|
+
plugins: options[:plugins],
|
144
|
+
creds_prompt: options[:creds_prompt]
|
135
145
|
)
|
136
146
|
write_file("Vagrantfile", contents, options)
|
137
147
|
FileUtils.cp(Orchestrate.source_root.join("templates", "vagrant", "dummy.box"),
|
@@ -177,8 +187,8 @@ module VagrantPlugins
|
|
177
187
|
contents = TemplateRenderer.render(Orchestrate.source_root.join("templates/environment/servers.json"),
|
178
188
|
environments: environments)
|
179
189
|
write_file("servers.json", contents, options)
|
180
|
-
@env.ui.info("You've created an environment
|
181
|
-
@env.ui.info("To complete the process you need to do the following: ")
|
190
|
+
@env.ui.info("You've created an environment-aware configuration.")
|
191
|
+
@env.ui.info("To complete the process, you need to do the following: ")
|
182
192
|
@env.ui.info(" 1. Add the target servers to servers.json")
|
183
193
|
@env.ui.info(" 2. Commit your changes")
|
184
194
|
@env.ui.info(" 3. Create a git branch for each environment")
|
@@ -1,14 +1,26 @@
|
|
1
1
|
require "optparse"
|
2
2
|
require "vagrant"
|
3
3
|
|
4
|
+
class Array
|
5
|
+
def in_groups(num_groups)
|
6
|
+
return [] if num_groups == 0
|
7
|
+
slice_size = (size / Float(num_groups)).ceil
|
8
|
+
each_slice(slice_size).to_a
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
4
12
|
module VagrantPlugins
|
5
13
|
module Orchestrate
|
6
14
|
module Command
|
7
15
|
class Push < Vagrant.plugin("2", :command)
|
8
16
|
include Vagrant::Util
|
9
17
|
|
18
|
+
@logger = Log4r::Logger.new("vagrant_orchestrate::command::push")
|
19
|
+
|
20
|
+
# rubocop:disable Metrics/AbcSize, MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
10
21
|
def execute
|
11
22
|
options = {}
|
23
|
+
options[:force] = @env.vagrantfile.config.orchestrate.force_push
|
12
24
|
|
13
25
|
opts = OptionParser.new do |o|
|
14
26
|
o.banner = "Usage: vagrant orchestrate push"
|
@@ -17,29 +29,105 @@ module VagrantPlugins
|
|
17
29
|
o.on("--reboot", "Reboot a managed server after the provisioning step") do
|
18
30
|
options[:reboot] = true
|
19
31
|
end
|
32
|
+
|
33
|
+
o.on("--strategy strategy", "The orchestration strategy to use. Default is serial") do |v|
|
34
|
+
options[:strategy] = v
|
35
|
+
end
|
36
|
+
|
37
|
+
o.on("-f", "--force", "Suppress prompting in between groups") do
|
38
|
+
options[:force] = true
|
39
|
+
end
|
20
40
|
end
|
21
41
|
|
22
42
|
# Parse the options
|
23
43
|
argv = parse_options(opts)
|
44
|
+
return unless argv
|
24
45
|
|
46
|
+
machines = []
|
25
47
|
with_target_vms(argv) do |machine|
|
26
|
-
|
27
|
-
|
28
|
-
|
48
|
+
if machine.provider_name.to_sym == :managed
|
49
|
+
machines << machine
|
50
|
+
else
|
51
|
+
@logger.debug("Skipping #{machine.name} because it doesn't use the :managed provider")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if machines.empty?
|
56
|
+
@env.ui.info("No servers with :managed provider found. Skipping.")
|
57
|
+
return
|
58
|
+
end
|
59
|
+
|
60
|
+
# This environment variable is used as a signal to the filtermanaged
|
61
|
+
# action so that we don't filter managed commands that are really just
|
62
|
+
# the implementation of a push action.
|
63
|
+
|
64
|
+
options[:parallel] = true
|
65
|
+
strategy = options[:strategy] || @env.vagrantfile.config.orchestrate.strategy
|
66
|
+
@env.ui.info("Pushing to managed servers using #{strategy} strategy.")
|
67
|
+
case strategy.to_sym
|
68
|
+
when :serial
|
69
|
+
options[:parallel] = false
|
70
|
+
result = deploy(options, machines)
|
71
|
+
when :parallel
|
72
|
+
result = deploy(options, machines)
|
73
|
+
when :canary
|
74
|
+
# A single canary server and then the rest
|
75
|
+
result = deploy(options, machines.take(1), machines.drop(1))
|
76
|
+
when :blue_green
|
77
|
+
# Split into two (almost) equal groups
|
78
|
+
groups = machines.in_groups(2)
|
79
|
+
result = deploy(options, groups.first, groups.last)
|
80
|
+
when :canary_blue_green
|
81
|
+
# A single canary and then two equal groups
|
82
|
+
canary = machines.take(1)
|
83
|
+
groups = machines.drop(1).in_groups(2)
|
84
|
+
result = deploy(options, canary, groups.first, groups.last)
|
85
|
+
else
|
86
|
+
@env.ui.error("Invalid deployment strategy specified")
|
87
|
+
result = false
|
88
|
+
end
|
89
|
+
|
90
|
+
return 1 unless result
|
91
|
+
0
|
92
|
+
end
|
93
|
+
# rubocop:enable Metrics/AbcSize, MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
94
|
+
|
95
|
+
def deploy(options, *groups)
|
96
|
+
groups.each_with_index do |machines, index|
|
97
|
+
@logger.debug("Orchestrating push to group number #{index + 1} of #{groups.size}.")
|
98
|
+
@logger.debug(" -- Hosts: #{machines.collect { |m| m.name.to_s }.join(',')}")
|
99
|
+
ENV["VAGRANT_ORCHESTRATE_COMMAND"] = "PUSH"
|
100
|
+
begin
|
101
|
+
batchify(machines, :up, options)
|
102
|
+
batchify(machines, :provision, options)
|
103
|
+
batchify(machines, :reload, options) if options[:reboot]
|
104
|
+
batchify(machines, :destroy, options)
|
105
|
+
@logger.debug("Finished orchestrating push to group number #{index + 1} of #{groups.size}.")
|
106
|
+
ensure
|
107
|
+
ENV.delete "VAGRANT_ORCHESTRATE_COMMAND"
|
29
108
|
end
|
30
|
-
|
109
|
+
|
110
|
+
# Don't prompt on the last group, that would be annoying
|
111
|
+
unless index == groups.size - 1 || options[:force]
|
112
|
+
return false unless prompt_for_continue
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def prompt_for_continue
|
118
|
+
result = @env.ui.ask("Deployment paused for manual review. Would you like to continue? (y/n)")
|
119
|
+
if result.upcase != "Y"
|
120
|
+
@env.ui.info("Deployment push action by user")
|
121
|
+
return false
|
31
122
|
end
|
123
|
+
true
|
32
124
|
end
|
33
125
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
machine.action(:reload, options) if options[:reboot]
|
40
|
-
machine.action(:destroy, options)
|
41
|
-
ensure
|
42
|
-
ENV.delete "VAGRANT_ORCHESTRATE_COMMAND"
|
126
|
+
def batchify(machines, action, options)
|
127
|
+
@env.batch(options[:parallel]) do |batch|
|
128
|
+
machines.each do |machine|
|
129
|
+
batch.action(machine, action, options)
|
130
|
+
end
|
43
131
|
end
|
44
132
|
end
|
45
133
|
end
|
@@ -6,8 +6,7 @@ module VagrantPlugins
|
|
6
6
|
module Command
|
7
7
|
class Root < Vagrant.plugin(2, :command)
|
8
8
|
def self.synopsis
|
9
|
-
|
10
|
-
repeatedly across multiple managed environments'
|
9
|
+
"Orchestrate provsioning of managed servers across environments"
|
11
10
|
end
|
12
11
|
|
13
12
|
def initialize(argv, env)
|
@@ -1,16 +1,92 @@
|
|
1
1
|
require "vagrant"
|
2
|
+
require "yaml"
|
2
3
|
|
3
4
|
module VagrantPlugins
|
4
5
|
module Orchestrate
|
5
6
|
class Config < Vagrant.plugin(2, :config)
|
6
7
|
attr_accessor :filter_managed_commands
|
8
|
+
attr_accessor :strategy
|
9
|
+
attr_accessor :force_push
|
10
|
+
attr_accessor :credentials
|
7
11
|
|
8
12
|
def initialize
|
9
13
|
@filter_managed_commands = UNSET_VALUE
|
14
|
+
@strategy = UNSET_VALUE
|
15
|
+
@force_push = UNSET_VALUE
|
16
|
+
@credentials = Credentials.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def credentials
|
20
|
+
yield @credentials if block_given?
|
21
|
+
@credentials
|
22
|
+
end
|
23
|
+
|
24
|
+
# It was a little hard to dig up, but this method gets called on the more general
|
25
|
+
# config object, with the more specific config as the argument.
|
26
|
+
# https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/config/v2/loader.rb
|
27
|
+
def merge(new_config)
|
28
|
+
super.tap do |result|
|
29
|
+
if new_config.credentials.unset?
|
30
|
+
result.credentials = @credentials
|
31
|
+
elsif @credentials.unset?
|
32
|
+
result.credentials = new_config.credentials
|
33
|
+
else
|
34
|
+
result.credentials = @credentials.merge(new_config.credentials)
|
35
|
+
end
|
36
|
+
end
|
10
37
|
end
|
11
38
|
|
12
39
|
def finalize!
|
13
40
|
@filter_managed_commands = false if @filter_managed_commands == UNSET_VALUE
|
41
|
+
@strategy = :serial if @strategy == UNSET_VALUE
|
42
|
+
@force_push = false if @force_push == UNSET_VALUE
|
43
|
+
@credentials = nil if @credentials.unset?
|
44
|
+
@credentials.finalize! if @credentials
|
45
|
+
end
|
46
|
+
|
47
|
+
class Credentials
|
48
|
+
# Same as Vagrant does to distinguish uninitialized variables and intentional assignments
|
49
|
+
# to Ruby's nil, we just have to define ourselves because we're in different scope
|
50
|
+
UNSET_VALUE = ::Vagrant::Plugin::V2::Config::UNSET_VALUE
|
51
|
+
|
52
|
+
attr_accessor :prompt
|
53
|
+
attr_accessor :file_path
|
54
|
+
attr_accessor :username
|
55
|
+
attr_accessor :password
|
56
|
+
|
57
|
+
def initialize
|
58
|
+
@prompt = UNSET_VALUE
|
59
|
+
@file_path = UNSET_VALUE
|
60
|
+
@username = UNSET_VALUE
|
61
|
+
@password = UNSET_VALUE
|
62
|
+
@unset = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def unset?
|
66
|
+
@unset || [@prompt, @file_path, @username, @password] == [UNSET_VALUE, UNSET_VALUE, UNSET_VALUE, UNSET_VALUE]
|
67
|
+
end
|
68
|
+
|
69
|
+
# Merge needs to be implemented here because this class doesn't get to
|
70
|
+
# to extend Vagrant.plugin(2, :config), and it would be pretty surprising
|
71
|
+
# if credentials configuration defined at different levels couldn't be merged
|
72
|
+
def merge(new_config)
|
73
|
+
result = dup
|
74
|
+
unless new_config.unset?
|
75
|
+
result.prompt = new_config.prompt unless new_config.prompt == UNSET_VALUE
|
76
|
+
result.file_path = new_config.file_path unless new_config.file_path == UNSET_VALUE
|
77
|
+
result.username = new_config.username unless new_config.username == UNSET_VALUE
|
78
|
+
result.password = new_config.password unless new_config.password == UNSET_VALUE
|
79
|
+
end
|
80
|
+
result
|
81
|
+
end
|
82
|
+
|
83
|
+
def finalize!
|
84
|
+
@unset = unset?
|
85
|
+
@prompt = nil if @prompt == UNSET_VALUE
|
86
|
+
@file_path = nil if @file_path == UNSET_VALUE
|
87
|
+
@username = nil if @username == UNSET_VALUE
|
88
|
+
@password = nil if @password == UNSET_VALUE
|
89
|
+
end
|
14
90
|
end
|
15
91
|
end
|
16
92
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "vagrant-orchestrate/action/filtermanaged"
|
2
|
+
require "vagrant-orchestrate/action/setcredentials"
|
2
3
|
|
3
4
|
begin
|
4
5
|
require "vagrant"
|
@@ -35,18 +36,22 @@ module VagrantPlugins
|
|
35
36
|
|
36
37
|
action_hook(:orchestrate, :machine_action_up) do |hook|
|
37
38
|
hook.prepend Action::FilterManaged
|
39
|
+
hook.prepend Action::SetCredentials
|
38
40
|
end
|
39
41
|
|
40
42
|
action_hook(:orchestrate, :machine_action_provision) do |hook|
|
41
43
|
hook.prepend Action::FilterManaged
|
44
|
+
hook.prepend Action::SetCredentials
|
42
45
|
end
|
43
46
|
|
44
47
|
action_hook(:orchestrate, :machine_action_destroy) do |hook|
|
45
48
|
hook.prepend Action::FilterManaged
|
49
|
+
hook.prepend Action::SetCredentials
|
46
50
|
end
|
47
51
|
|
48
52
|
action_hook(:orchestrate, :machine_action_reload) do |hook|
|
49
53
|
hook.prepend Action::FilterManaged
|
54
|
+
hook.prepend Action::SetCredentials
|
50
55
|
end
|
51
56
|
|
52
57
|
# This initializes the internationalization strings.
|
@@ -14,6 +14,12 @@ Vagrant.configure("2") do |config|
|
|
14
14
|
# This disables up, provision, reload, and destroy for managed servers. Use
|
15
15
|
# `vagrant orchestrate push` to communicate with managed servers.
|
16
16
|
config.orchestrate.filter_managed_commands = true
|
17
|
+
<% if creds_prompt -%>
|
18
|
+
config.orchestrate.credentials.prompt = true
|
19
|
+
<% end -%>
|
20
|
+
<% if creds_file_path -%>
|
21
|
+
config.orchestrate.credentials.file_path = "<%= creds_file_path%>"
|
22
|
+
<% end -%>
|
17
23
|
|
18
24
|
<% if provisioners.include? "shell" -%>
|
19
25
|
<% shell_paths.each do |path| -%>
|
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
|
+
version: 0.4.0
|
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-
|
11
|
+
date: 2015-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,9 +80,11 @@ files:
|
|
80
80
|
- LICENSE
|
81
81
|
- README.md
|
82
82
|
- Rakefile
|
83
|
+
- docs/strategy.md
|
83
84
|
- dummy.box
|
84
85
|
- lib/vagrant-orchestrate.rb
|
85
86
|
- lib/vagrant-orchestrate/action/filtermanaged.rb
|
87
|
+
- lib/vagrant-orchestrate/action/setcredentials.rb
|
86
88
|
- lib/vagrant-orchestrate/command/init.rb
|
87
89
|
- lib/vagrant-orchestrate/command/push.rb
|
88
90
|
- lib/vagrant-orchestrate/command/root.rb
|