vagrant-orchestrate 0.3.2 → 0.4.0
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 +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
|