From fdce74475c2c9add9aaf2d2183dd0c47bfe949a0 Mon Sep 17 00:00:00 2001
From: Jonathan Collins
Date: Fri, 14 Nov 2014 19:31:19 -0800
Subject: [PATCH 001/203] typo
---
website/docs/source/v2/share/connect.html.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/website/docs/source/v2/share/connect.html.md b/website/docs/source/v2/share/connect.html.md
index 37a3bf8e9..c7074d675 100644
--- a/website/docs/source/v2/share/connect.html.md
+++ b/website/docs/source/v2/share/connect.html.md
@@ -29,7 +29,7 @@ machines. `vagrant connect` creates a tiny virtual machine that takes up
only around 20 MB in RAM, using VirtualBox or VMware (more provider support
is coming soon).
-Any traffic sent to this tiny virtual machine is then proxies through to
+Any traffic sent to this tiny virtual machine is then proxied through to
the shared Vagrant environment as if it were directed at it.
## Beware: Vagrant Insecure Key
From 17673fafcd81ab2562f5810d14a145614af9c8a7 Mon Sep 17 00:00:00 2001
From: Emilien Kenler
Date: Tue, 18 Nov 2014 11:05:59 +0900
Subject: [PATCH 002/203] You need to press enter to migrate from 1.1 to 1.5
---
templates/locales/en.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index 81365587d..837f522e1 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -243,7 +243,7 @@ en:
Press ctrl-c now to exit if you want to remove some boxes or free
up some disk space.
- Press any other key to continue.
+ Press the Enter or Return key to continue.
version_current: |-
Installed Version: %{version}
version_latest: |-
From 5ae5690d66207db72e8a2c50def69c221d83aea2 Mon Sep 17 00:00:00 2001
From: Dharma Bellamkonda
Date: Fri, 28 Nov 2014 12:59:20 -0700
Subject: [PATCH 003/203] clarify documentation of docker.link()
---
website/docs/source/v2/docker/configuration.html.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/website/docs/source/v2/docker/configuration.html.md b/website/docs/source/v2/docker/configuration.html.md
index a8dfed3c7..73bde2df3 100644
--- a/website/docs/source/v2/docker/configuration.html.md
+++ b/website/docs/source/v2/docker/configuration.html.md
@@ -36,7 +36,8 @@ General settings:
but not to the host machine. Useful for links.
* `link` (method, string argument) - Link this container to another
- by name. Example: `docker.link("db:db")`. Note, if you're linking to
+ by name. The argument should be in the format of `(name:alias)`.
+ Example: `docker.link("db:db")`. Note, if you're linking to
another container in the same Vagrantfile, make sure you call
`vagrant up` with the `--no-parallel` flag.
From 306c4f7edaa9ee6acbfb6bd922224f694537b6eb Mon Sep 17 00:00:00 2001
From: Gilles Cornu
Date: Sat, 29 Nov 2014 23:29:46 +0100
Subject: [PATCH 004/203] provisioners/ansible: force --connection=ssh
When `--connection` argument is not specified, Ansible will use the
'smart' mode, which can either use `ssh` or `paramiko` transports,
depending of the version of OpenSSH available. If OpenSSH version is new
enough to support ControlPersist technology, `ssh` will be used.
See also http://docs.ansible.com/intro_configuration.html#transport.
In order to support some advanced features of Vagrant (e.g. multiple ssh
private key identities or ssh forwarding), the Ansible provisioner
already must force `ssh` connection mode.
Having to deal with the possible fallback to `paramiko` increase the
burden of special cases that Ansible provisioner must handle, without
any added value, as Vagrant is based on OpenSSH and its users are
usually using modern operating systems.
With this change, the Ansible provisioner will officially only support
`ssh`. It will still be possible to switch to another connection mode
via `raw_arguments`, but it will breach the "contract", and no
(community) support can be expected in such use case.
ref #3900, #3396
---
CHANGELOG.md | 1 +
plugins/provisioners/ansible/provisioner.rb | 22 +++---
.../provisioners/ansible/provisioner_test.rb | 76 +++++++------------
.../source/v2/provisioning/ansible.html.md | 7 +-
4 files changed, 46 insertions(+), 60 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 53565b085..bb43c8d7b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -88,6 +88,7 @@ BUG FIXES:
IP address and don't allow it. [GH-4671]
- providers/virtualbox: Show more descriptive error if VirtualBox is
reporting an empty version. [GH-4657]
+ - provisioners/ansible: Force `ssh` (OpenSSH) connection by default [GH-3396]
- provisioners/docker: Get GPG key over SSL. [GH-4597]
- provisioners/docker: Search for docker binary in multiple places. [GH-4580]
- provisioners/salt: Highstate works properly with a master. [GH-4471]
diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb
index e43c81a96..cf32203d1 100644
--- a/plugins/provisioners/ansible/provisioner.rb
+++ b/plugins/provisioners/ansible/provisioner.rb
@@ -18,11 +18,10 @@ module VagrantPlugins
# Connect with Vagrant SSH identity
options = %W[--private-key=#{@ssh_info[:private_key_path][0]} --user=#{@ssh_info[:username]}]
- # Multiple SSH keys and/or SSH forwarding can be passed via
- # ANSIBLE_SSH_ARGS environment variable, which requires 'ssh' mode.
- # Note that multiple keys and ssh-forwarding settings are not supported
- # by deprecated 'paramiko' mode.
- options << "--connection=ssh" unless ansible_ssh_args.empty?
+ # Connect with native OpenSSH client
+ # Other modes (e.g. paramiko) are not officially supported,
+ # but can be enabled via raw_arguments option.
+ options << "--connection=ssh"
# By default we limit by the current machine.
# This can be overridden by the limit config option.
@@ -54,16 +53,17 @@ module VagrantPlugins
# Assemble the full ansible-playbook command
command = (%w(ansible-playbook) << options << config.playbook).flatten
- # Some Ansible options must be passed as environment variables
env = {
- "ANSIBLE_FORCE_COLOR" => "true",
- "ANSIBLE_HOST_KEY_CHECKING" => "#{config.host_key_checking}",
-
# Ensure Ansible output isn't buffered so that we receive output
# on a task-by-task basis.
- "PYTHONUNBUFFERED" => 1
+ "PYTHONUNBUFFERED" => 1,
+
+ # Some Ansible options must be passed as environment variables,
+ # as there is no equivalent command line arguments
+ "ANSIBLE_FORCE_COLOR" => "true",
+ "ANSIBLE_HOST_KEY_CHECKING" => "#{config.host_key_checking}",
}
- # Support Multiple SSH keys and SSH forwarding:
+ # ANSIBLE_SSH_ARGS is required for Multiple SSH keys, SSH forwarding and custom SSH settings
env["ANSIBLE_SSH_ARGS"] = ansible_ssh_args unless ansible_ssh_args.empty?
show_ansible_playbook_command(env, command) if (config.verbose || @logger.debug?)
diff --git a/test/unit/plugins/provisioners/ansible/provisioner_test.rb b/test/unit/plugins/provisioners/ansible/provisioner_test.rb
index f93f1f53b..eead86925 100644
--- a/test/unit/plugins/provisioners/ansible/provisioner_test.rb
+++ b/test/unit/plugins/provisioners/ansible/provisioner_test.rb
@@ -62,13 +62,16 @@ VF
# Class methods for code reuse across examples
#
- def self.it_should_set_arguments_and_environment_variables(expected_args_count = 5, expected_vars_count = 3, expected_host_key_checking = false)
+ def self.it_should_set_arguments_and_environment_variables(
+ expected_args_count = 6, expected_vars_count = 3, expected_host_key_checking = false, expected_transport_mode = "ssh")
+
it "sets implicit arguments in a specific order" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
expect(args[0]).to eq("ansible-playbook")
expect(args[1]).to eq("--private-key=#{machine.ssh_info[:private_key_path][0]}")
expect(args[2]).to eq("--user=#{machine.ssh_info[:username]}")
+ expect(args[3]).to eq("--connection=ssh")
inventory_count = args.count { |x| x =~ /^--inventory-file=.+$/ }
expect(inventory_count).to be > 0
@@ -111,6 +114,15 @@ VF
expect(args.last[:env].length).to eq(expected_vars_count)
}
end
+
+ it "enables '#{expected_transport_mode}' transport mode" do
+ expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
+ index = args.rindex("--connection=#{expected_transport_mode}")
+ expect(index).to be > 0
+ expect(find_last_argument_after(index, args, /--connection=\w+/)).to be_false
+ }
+ end
+
end
def self.it_should_set_optional_arguments(arg_map)
@@ -128,35 +140,7 @@ VF
end
end
- def self.it_should_use_smart_transport_mode
- it "does not export ANSIBLE_SSH_ARGS" do
- expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
- cmd_opts = args.last
- expect(cmd_opts[:env]['ANSIBLE_SSH_ARGS']).to be_nil
- }
- end
-
- it "does not force any transport mode" do
- expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
- total = args.count { |x| x =~ /^--connection=\w+$/ }
- expect(total).to eql(0)
- }
- end
- end
-
- def self.it_should_use_transport_mode(transport_mode)
- it "enables '#{transport_mode}' transport mode" do
- expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
- index = args.rindex("--connection=#{transport_mode}")
- expect(index).to be > 0
- expect(find_last_argument_after(index, args, /--connection=\w+/)).to be_false
- }
- end
- end
-
- def self.it_should_force_ssh_transport_mode
- it_should_use_transport_mode('ssh')
-
+ def self.it_should_explicitly_enable_ansible_ssh_control_persist_defaults
it "configures ControlPersist (like Ansible defaults) via ANSIBLE_SSH_ARGS" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
cmd_opts = args.last
@@ -212,7 +196,6 @@ VF
describe "with default options" do
it_should_set_arguments_and_environment_variables
- it_should_use_smart_transport_mode
it_should_create_and_use_generated_inventory
it "does not add any group section to the generated inventory" do
@@ -281,8 +264,7 @@ VF
config.host_key_checking = true
end
- it_should_set_arguments_and_environment_variables 5, 3, true
- it_should_use_smart_transport_mode
+ it_should_set_arguments_and_environment_variables 6, 3, true
end
describe "with boolean (flag) options disabled" do
@@ -294,7 +276,7 @@ VF
config.sudo_user = 'root'
end
- it_should_set_arguments_and_environment_variables 6
+ it_should_set_arguments_and_environment_variables 7
it_should_set_optional_arguments({ "sudo_user" => "--sudo-user=root" })
it "it does not set boolean flag when corresponding option is set to false" do
@@ -321,9 +303,8 @@ VF
"--new-arg=yeah"]
end
- it_should_set_arguments_and_environment_variables 15
+ it_should_set_arguments_and_environment_variables 16, 3, false, "paramiko"
it_should_create_and_use_generated_inventory
- it_should_use_transport_mode('paramiko')
it "sets all raw arguments" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
@@ -361,7 +342,6 @@ VF
end
it_should_set_arguments_and_environment_variables
- it_should_use_smart_transport_mode
it "does not generate the inventory and uses given inventory path instead" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
@@ -377,7 +357,7 @@ VF
config.ask_vault_pass = true
end
- it_should_set_arguments_and_environment_variables 6
+ it_should_set_arguments_and_environment_variables 7
it "should ask the vault password" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
@@ -391,7 +371,7 @@ VF
config.vault_password_file = existing_file
end
- it_should_set_arguments_and_environment_variables 6
+ it_should_set_arguments_and_environment_variables 7
it "uses the given vault password file" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
@@ -406,7 +386,7 @@ VF
end
it_should_set_arguments_and_environment_variables 6, 4
- it_should_force_ssh_transport_mode
+ it_should_explicitly_enable_ansible_ssh_control_persist_defaults
it "passes custom SSH options via ANSIBLE_SSH_ARGS with the highest priority" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
@@ -440,7 +420,7 @@ VF
end
it_should_set_arguments_and_environment_variables 6, 4
- it_should_force_ssh_transport_mode
+ it_should_explicitly_enable_ansible_ssh_control_persist_defaults
it "passes additional Identity Files via ANSIBLE_SSH_ARGS" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
@@ -457,7 +437,7 @@ VF
end
it_should_set_arguments_and_environment_variables 6, 4
- it_should_force_ssh_transport_mode
+ it_should_explicitly_enable_ansible_ssh_control_persist_defaults
it "enables SSH-Forwarding via ANSIBLE_SSH_ARGS" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
@@ -475,7 +455,7 @@ VF
it "shows the ansible-playbook command" do
expect(machine.env.ui).to receive(:detail).with { |full_command|
- expect(full_command).to eq("ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false PYTHONUNBUFFERED=1 ansible-playbook --private-key=/path/to/my/key --user=testuser --limit='machine1' --inventory-file=#{generated_inventory_dir} playbook.yml")
+ expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --limit='machine1' --inventory-file=#{generated_inventory_dir} playbook.yml")
}
end
end
@@ -485,12 +465,12 @@ VF
config.verbose = 'v'
end
- it_should_set_arguments_and_environment_variables 6
+ it_should_set_arguments_and_environment_variables 7
it_should_set_optional_arguments({ "verbose" => "-v" })
it "shows the ansible-playbook command" do
expect(machine.env.ui).to receive(:detail).with { |full_command|
- expect(full_command).to eq("ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false PYTHONUNBUFFERED=1 ansible-playbook --private-key=/path/to/my/key --user=testuser --limit='machine1' --inventory-file=#{generated_inventory_dir} -v playbook.yml")
+ expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --limit='machine1' --inventory-file=#{generated_inventory_dir} -v playbook.yml")
}
end
end
@@ -524,7 +504,7 @@ VF
end
it_should_set_arguments_and_environment_variables 20, 4, true
- it_should_force_ssh_transport_mode
+ it_should_explicitly_enable_ansible_ssh_control_persist_defaults
it_should_set_optional_arguments({ "extra_vars" => "--extra-vars=@#{File.expand_path(__FILE__)}",
"sudo" => "--sudo",
"sudo_user" => "--sudo-user=deployer",
@@ -537,7 +517,7 @@ VF
"limit" => "--limit=machine*:&vagrant:!that_one",
"start_at_task" => "--start-at-task=an awesome task",
})
-
+
it "also includes given raw arguments" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
expect(args).to include("--su-user=foot")
@@ -548,7 +528,7 @@ VF
it "shows the ansible-playbook command, with additional quotes when required" do
expect(machine.env.ui).to receive(:detail).with { |full_command|
- expect(full_command).to eq("ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=true PYTHONUNBUFFERED=1 ANSIBLE_SSH_ARGS='-o IdentityFile=/my/key2 -o ForwardAgent=yes -o ControlMaster=no -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/my/key1 --user=testuser --connection=ssh --why-not --su-user=foot --ask-su-pass --limit='all' --inventory-file=#{generated_inventory_dir} --extra-vars=@#{File.expand_path(__FILE__)} --sudo --sudo-user=deployer -vvv --ask-sudo-pass --ask-vault-pass --vault-password-file=#{File.expand_path(__FILE__)} --tags=db,www --skip-tags=foo,bar --limit='machine*:&vagrant:!that_one' --start-at-task='an awesome task' playbook.yml")
+ expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=true ANSIBLE_SSH_ARGS='-o IdentityFile=/my/key2 -o ForwardAgent=yes -o ControlMaster=no -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/my/key1 --user=testuser --connection=ssh --why-not --su-user=foot --ask-su-pass --limit='all' --inventory-file=#{generated_inventory_dir} --extra-vars=@#{File.expand_path(__FILE__)} --sudo --sudo-user=deployer -vvv --ask-sudo-pass --ask-vault-pass --vault-password-file=#{File.expand_path(__FILE__)} --tags=db,www --skip-tags=foo,bar --limit='machine*:&vagrant:!that_one' --start-at-task='an awesome task' playbook.yml")
}
end
end
diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md
index a39315bba..7be6b23ce 100644
--- a/website/docs/source/v2/provisioning/ansible.html.md
+++ b/website/docs/source/v2/provisioning/ansible.html.md
@@ -8,7 +8,7 @@ sidebar_current: "provisioning-ansible"
**Provisioner name: `"ansible"`**
The ansible provisioner allows you to provision the guest using
-[Ansible](http://ansible.com) playbooks.
+[Ansible](http://ansible.com) playbooks by executing `ansible-playbook` from the Vagrant host.
Ansible playbooks are [YAML](http://en.wikipedia.org/wiki/YAML) documents that
comprise the set of steps to be orchestrated on one or more machines. This documentation
@@ -25,6 +25,11 @@ a single page of documentation.
+## Setup Requirements
+
+* [Install Ansible](http://docs.ansible.com/intro_installation.html#installing-the-control-machine) on your Vagrant host.
+* Your Vagrant host should ideally provide a recent version of OpenSSH that [supports ControlPersist](http://docs.ansible.com/faq.html#how-do-i-get-ansible-to-reuse-connections-enable-kerberized-ssh-or-have-ansible-pay-attention-to-my-local-ssh-config-file)
+
## Inventory File
When using Ansible, it needs to know on which machines a given playbook should run. It does
From 178942cf274391151460aaff44da34ef05f2e73c Mon Sep 17 00:00:00 2001
From: Gilles Cornu
Date: Sun, 30 Nov 2014 02:02:29 +0100
Subject: [PATCH 005/203] provisioners/ansible: change arguments arrangement
- force `--connection=ssh` (any other modes like paramiko or smart are not
supported)
- give the highest priority to `raw_arguments` for sake of simplicity (in
usage, in code and in documentation)
- fix position of the `--limit` argument (the generated inventory could be
shadowed by `raw_arguments`, while ansible.limit was able to override
`raw_arguments`
ref #3396
---
CHANGELOG.md | 6 ++++
plugins/provisioners/ansible/provisioner.rb | 30 ++++++++---------
.../provisioners/ansible/provisioner_test.rb | 32 +++++++++++--------
.../source/v2/provisioning/ansible.html.md | 4 +--
4 files changed, 40 insertions(+), 32 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bb43c8d7b..434f790ea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
## 1.7.0 (unreleased)
+BREAKING CHANGES:
+
+ - provisioners/ansible: `raw_arguments` has now highest priority
+ - provisioners/ansible: only the `ssh` connection transport is supported
+ (`paramiko` can be enabled with `raw_arguments` at your own risks)
+
FEATURES:
- **Named provisioners**: Provisioners can now be named. This name is used
diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb
index cf32203d1..bb6b25ce1 100644
--- a/plugins/provisioners/ansible/provisioner.rb
+++ b/plugins/provisioners/ansible/provisioner.rb
@@ -12,7 +12,7 @@ module VagrantPlugins
@ssh_info = @machine.ssh_info
#
- # 1) Default Settings (lowest precedence)
+ # Ansible provisioner options
#
# Connect with Vagrant SSH identity
@@ -23,19 +23,13 @@ module VagrantPlugins
# but can be enabled via raw_arguments option.
options << "--connection=ssh"
- # By default we limit by the current machine.
- # This can be overridden by the limit config option.
- options << "--limit=#{@machine.name}" unless config.limit
-
- #
- # 2) Configuration Joker
- #
-
- options.concat(self.as_array(config.raw_arguments)) if config.raw_arguments
-
- #
- # 3) Append Provisioner options (highest precedence):
- #
+ # By default we limit by the current machine, but
+ # this can be overridden by the `limit` option.
+ if config.limit
+ options << "--limit=#{as_list_argument(config.limit)}"
+ else
+ options << "--limit=#{@machine.name}"
+ end
options << "--inventory-file=#{self.setup_inventory_file}"
options << "--extra-vars=#{self.get_extra_vars_argument}" if config.extra_vars
@@ -47,10 +41,16 @@ module VagrantPlugins
options << "--vault-password-file=#{config.vault_password_file}" if config.vault_password_file
options << "--tags=#{as_list_argument(config.tags)}" if config.tags
options << "--skip-tags=#{as_list_argument(config.skip_tags)}" if config.skip_tags
- options << "--limit=#{as_list_argument(config.limit)}" if config.limit
options << "--start-at-task=#{config.start_at_task}" if config.start_at_task
+ # Finally, add the configuration joker, which has the highest precedence and
+ # can therefore potentially override any other options of this provisioner.
+ options.concat(self.as_array(config.raw_arguments)) if config.raw_arguments
+
+ #
# Assemble the full ansible-playbook command
+ #
+
command = (%w(ansible-playbook) << options << config.playbook).flatten
env = {
diff --git a/test/unit/plugins/provisioners/ansible/provisioner_test.rb b/test/unit/plugins/provisioners/ansible/provisioner_test.rb
index eead86925..e666b51a4 100644
--- a/test/unit/plugins/provisioners/ansible/provisioner_test.rb
+++ b/test/unit/plugins/provisioners/ansible/provisioner_test.rb
@@ -82,18 +82,18 @@ VF
it "sets --limit argument" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
- raw_limits = []
+ all_limits = args.select { |x| x =~ /^(--limit=|-l)/ }
if config.raw_arguments
raw_limits = config.raw_arguments.select { |x| x =~ /^(--limit=|-l)/ }
- end
- all_limits = args.select { |x| x =~ /^(--limit=|-l)/ }
- expect(all_limits.length - raw_limits.length).to eq(1)
-
- if config.limit
- limit = config.limit.kind_of?(Array) ? config.limit.join(',') : config.limit
- expect(all_limits.last).to eq("--limit=#{limit}")
+ expect(all_limits.length - raw_limits.length).to eq(1)
+ expect(all_limits.last).to eq(raw_limits.last)
else
- expect(all_limits.first).to eq("--limit=#{machine.name}")
+ if config.limit
+ limit = config.limit.kind_of?(Array) ? config.limit.join(',') : config.limit
+ expect(all_limits.last).to eq("--limit=#{limit}")
+ else
+ expect(all_limits.first).to eq("--limit=#{machine.name}")
+ end
end
}
end
@@ -292,6 +292,7 @@ VF
before do
config.sudo = false
config.skip_tags = %w(foo bar)
+ config.limit = "all"
config.raw_arguments = ["--connection=paramiko",
"--skip-tags=ignored",
"--module-path=/other/modules",
@@ -300,11 +301,11 @@ VF
"--limit=foo",
"--limit=bar",
"--inventory-file=/forget/it/my/friend",
+ "--user=lion",
"--new-arg=yeah"]
end
- it_should_set_arguments_and_environment_variables 16, 3, false, "paramiko"
- it_should_create_and_use_generated_inventory
+ it_should_set_arguments_and_environment_variables 17, 3, false, "paramiko"
it "sets all raw arguments" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
@@ -314,9 +315,12 @@ VF
}
end
- it "sets raw arguments before arguments related to supported options" do
+ it "sets raw arguments after arguments related to supported options" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
- expect(args.index("--skip-tags=foo,bar")).to be > args.index("--skip-tags=ignored")
+ expect(args.index("--user=lion")).to be > args.index("--user=testuser")
+ expect(args.index("--inventory-file=/forget/it/my/friend")).to be > args.index("--inventory-file=#{generated_inventory_dir}")
+ expect(args.index("--limit=bar")).to be > args.index("--limit=all")
+ expect(args.index("--skip-tags=ignored")).to be > args.index("--skip-tags=foo,bar")
}
end
@@ -528,7 +532,7 @@ VF
it "shows the ansible-playbook command, with additional quotes when required" do
expect(machine.env.ui).to receive(:detail).with { |full_command|
- expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=true ANSIBLE_SSH_ARGS='-o IdentityFile=/my/key2 -o ForwardAgent=yes -o ControlMaster=no -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/my/key1 --user=testuser --connection=ssh --why-not --su-user=foot --ask-su-pass --limit='all' --inventory-file=#{generated_inventory_dir} --extra-vars=@#{File.expand_path(__FILE__)} --sudo --sudo-user=deployer -vvv --ask-sudo-pass --ask-vault-pass --vault-password-file=#{File.expand_path(__FILE__)} --tags=db,www --skip-tags=foo,bar --limit='machine*:&vagrant:!that_one' --start-at-task='an awesome task' playbook.yml")
+ expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=true ANSIBLE_SSH_ARGS='-o IdentityFile=/my/key2 -o ForwardAgent=yes -o ControlMaster=no -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/my/key1 --user=testuser --connection=ssh --limit='machine*:&vagrant:!that_one' --inventory-file=#{generated_inventory_dir} --extra-vars=@#{File.expand_path(__FILE__)} --sudo --sudo-user=deployer -vvv --ask-sudo-pass --ask-vault-pass --vault-password-file=#{File.expand_path(__FILE__)} --tags=db,www --skip-tags=foo,bar --start-at-task='an awesome task' --why-not --su-user=foot --ask-su-pass --limit='all' playbook.yml")
}
end
end
diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md
index 7be6b23ce..6c79721e1 100644
--- a/website/docs/source/v2/provisioning/ansible.html.md
+++ b/website/docs/source/v2/provisioning/ansible.html.md
@@ -196,9 +196,7 @@ by the sudo command.
* `ansible.tags` can be set to a string or an array of tags. Only plays, roles and tasks tagged with these values will be executed.
* `ansible.skip_tags` can be set to a string or an array of tags. Only plays, roles and tasks that *do not match* these values will be executed.
* `ansible.start_at_task` can be set to a string corresponding to the task name where the playbook provision will start.
-* `ansible.raw_arguments` can be set to an array of strings corresponding to a list of `ansible-playbook` arguments (e.g. `['--check', '-M /my/modules']`). It is an *unsafe wildcard* that can be used to apply Ansible options that are not (yet) supported by this Vagrant provisioner. Following precedence rules apply:
- * Any supported options (described above) will override conflicting `raw_arguments` value (e.g. `--tags` or `--start-at-task`)
- * Vagrant default user authentication can be overridden via `raw_arguments` (with custom values for `--user` and `--private-key`)
+* `ansible.raw_arguments` can be set to an array of strings corresponding to a list of `ansible-playbook` arguments (e.g. `['--check', '-M /my/modules']`). It is an *unsafe wildcard* that can be used to apply Ansible options that are not (yet) supported by this Vagrant provisioner. As of Vagrant 1.7, `raw_arguments` has the highest priority and its values can potentially override or break other Vagrant settings.
* `ansible.raw_ssh_args` can be set to an array of strings corresponding to a list of OpenSSH client parameters (e.g. `['-o ControlMaster=no']`). It is an *unsafe wildcard* that can be used to pass additional SSH settings to Ansible via `ANSIBLE_SSH_ARGS` environment variable.
* `ansible.host_key_checking` can be set to `true` which will enable host key checking. As Vagrant 1.5, the default value is `false`, to avoid connection problems when creating new virtual machines.
From f96636587a9d74be260bc23a183d5392956496f0 Mon Sep 17 00:00:00 2001
From: Gilles Cornu
Date: Sun, 30 Nov 2014 06:55:21 +0100
Subject: [PATCH 006/203] provisioners/ansible: don't read/write known_hosts
Like Vagrant's default SSH behaviors (e.g ssh or ssh-config commands),
the Ansible provisioner should by default not modify or read the user
known host file (e.g. ~/.ssh/known_hosts).
Given that `UserKnownHostsFile=/dev/null` SSH option is usually combined
with `StrictHostKeyChecking=no`, it seems quite reasonable to bind the
activation/disactivation of both options to `host_key_checking`
provisioner attribute.
For the records, a discussion held in Ansible-Development mailing list
clearly confirmed that there is no short-term plan to adapt Ansible to
offer an extra option or change the behavior of
ANSIBLE_HOST_KEY_CHECKING. For this reason, the current implementation
seems reasonable and should be stable on the long run.
Close #3900
Related References:
- https://groups.google.com/forum/#!msg/ansible-devel/iuoZs1oImNs/6xrj5oa1CmoJ
- https://github.com/ansible/ansible/issues/9442
---
CHANGELOG.md | 2 ++
plugins/provisioners/ansible/provisioner.rb | 5 +++++
.../provisioners/ansible/provisioner_test.rb | 14 ++++++++++----
.../docs/source/v2/provisioning/ansible.html.md | 2 +-
4 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 434f790ea..42e753943 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -95,6 +95,8 @@ BUG FIXES:
- providers/virtualbox: Show more descriptive error if VirtualBox is
reporting an empty version. [GH-4657]
- provisioners/ansible: Force `ssh` (OpenSSH) connection by default [GH-3396]
+ - provisioners/ansible: Don't use or modify `~/.ssh/known_hosts` file by default,
+ similarly to native vagrant commands [GH-3900]
- provisioners/docker: Get GPG key over SSL. [GH-4597]
- provisioners/docker: Search for docker binary in multiple places. [GH-4580]
- provisioners/salt: Highstate works properly with a master. [GH-4471]
diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb
index bb6b25ce1..e403b561f 100644
--- a/plugins/provisioners/ansible/provisioner.rb
+++ b/plugins/provisioners/ansible/provisioner.rb
@@ -183,9 +183,14 @@ module VagrantPlugins
@ansible_ssh_args ||= get_ansible_ssh_args
end
+ # Use ANSIBLE_SSH_ARGS to pass some OpenSSH options that are not wrapped by
+ # an ad-hoc Ansible option. Last update corresponds to Ansible 1.8
def get_ansible_ssh_args
ssh_options = []
+ # Don't access user's known_hosts file, except when host_key_checking is enabled.
+ ssh_options << "-o UserKnownHostsFile=/dev/null" unless config.host_key_checking
+
# Multiple Private Keys
@ssh_info[:private_key_path].drop(1).each do |key|
ssh_options << "-o IdentityFile=#{key}"
diff --git a/test/unit/plugins/provisioners/ansible/provisioner_test.rb b/test/unit/plugins/provisioners/ansible/provisioner_test.rb
index e666b51a4..756f95769 100644
--- a/test/unit/plugins/provisioners/ansible/provisioner_test.rb
+++ b/test/unit/plugins/provisioners/ansible/provisioner_test.rb
@@ -63,7 +63,7 @@ VF
#
def self.it_should_set_arguments_and_environment_variables(
- expected_args_count = 6, expected_vars_count = 3, expected_host_key_checking = false, expected_transport_mode = "ssh")
+ expected_args_count = 6, expected_vars_count = 4, expected_host_key_checking = false, expected_transport_mode = "ssh")
it "sets implicit arguments in a specific order" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
@@ -101,6 +101,12 @@ VF
it "exports environment variables" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
cmd_opts = args.last
+
+ if expected_host_key_checking
+ expect(cmd_opts[:env]['ANSIBLE_SSH_ARGS']).to be_nil unless config.raw_arguments
+ else
+ expect(cmd_opts[:env]['ANSIBLE_SSH_ARGS']).to include("-o UserKnownHostsFile=/dev/null")
+ end
expect(cmd_opts[:env]['ANSIBLE_FORCE_COLOR']).to eql("true")
expect(cmd_opts[:env]['ANSIBLE_HOST_KEY_CHECKING']).to eql(expected_host_key_checking.to_s)
expect(cmd_opts[:env]['PYTHONUNBUFFERED']).to eql(1)
@@ -305,7 +311,7 @@ VF
"--new-arg=yeah"]
end
- it_should_set_arguments_and_environment_variables 17, 3, false, "paramiko"
+ it_should_set_arguments_and_environment_variables 17, 4, false, "paramiko"
it "sets all raw arguments" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
@@ -459,7 +465,7 @@ VF
it "shows the ansible-playbook command" do
expect(machine.env.ui).to receive(:detail).with { |full_command|
- expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --limit='machine1' --inventory-file=#{generated_inventory_dir} playbook.yml")
+ expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ANSIBLE_SSH_ARGS='-o UserKnownHostsFile=/dev/null -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --limit='machine1' --inventory-file=#{generated_inventory_dir} playbook.yml")
}
end
end
@@ -474,7 +480,7 @@ VF
it "shows the ansible-playbook command" do
expect(machine.env.ui).to receive(:detail).with { |full_command|
- expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --limit='machine1' --inventory-file=#{generated_inventory_dir} -v playbook.yml")
+ expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ANSIBLE_SSH_ARGS='-o UserKnownHostsFile=/dev/null -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --limit='machine1' --inventory-file=#{generated_inventory_dir} -v playbook.yml")
}
end
end
diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md
index 6c79721e1..9301e0fb8 100644
--- a/website/docs/source/v2/provisioning/ansible.html.md
+++ b/website/docs/source/v2/provisioning/ansible.html.md
@@ -198,7 +198,7 @@ by the sudo command.
* `ansible.start_at_task` can be set to a string corresponding to the task name where the playbook provision will start.
* `ansible.raw_arguments` can be set to an array of strings corresponding to a list of `ansible-playbook` arguments (e.g. `['--check', '-M /my/modules']`). It is an *unsafe wildcard* that can be used to apply Ansible options that are not (yet) supported by this Vagrant provisioner. As of Vagrant 1.7, `raw_arguments` has the highest priority and its values can potentially override or break other Vagrant settings.
* `ansible.raw_ssh_args` can be set to an array of strings corresponding to a list of OpenSSH client parameters (e.g. `['-o ControlMaster=no']`). It is an *unsafe wildcard* that can be used to pass additional SSH settings to Ansible via `ANSIBLE_SSH_ARGS` environment variable.
-* `ansible.host_key_checking` can be set to `true` which will enable host key checking. As Vagrant 1.5, the default value is `false`, to avoid connection problems when creating new virtual machines.
+* `ansible.host_key_checking` can be set to `true` which will enable host key checking. As of Vagrant 1.5, the default value is `false` and as of Vagrant 1.7 the user kownn host file (e.g. `~/.ssh/known_hosts`) is no longer read nor modified. In other words: by default, the Ansible provisioner behaves the same as Vagrant native commands (e.g `vagrant ssh`).
## Tips and Tricks
From 72afdce6305aa3564a065f0457b1dd38db3939e2 Mon Sep 17 00:00:00 2001
From: Ken Crowell
Date: Tue, 2 Dec 2014 17:25:30 -0400
Subject: [PATCH 007/203] Issue #4895: Support grains config for salt
---
plugins/provisioners/salt/config.rb | 10 ++++++++++
plugins/provisioners/salt/provisioner.rb | 7 ++++++-
templates/locales/en.yml | 2 ++
.../plugins/provisioners/salt/config_test.rb | 18 ++++++++++++++++++
.../docs/source/v2/provisioning/salt.html.md | 3 ++-
5 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/plugins/provisioners/salt/config.rb b/plugins/provisioners/salt/config.rb
index 0a99d3fc8..4d97d942c 100644
--- a/plugins/provisioners/salt/config.rb
+++ b/plugins/provisioners/salt/config.rb
@@ -12,6 +12,7 @@ module VagrantPlugins
attr_accessor :master_config
attr_accessor :master_key
attr_accessor :master_pub
+ attr_accessor :grains_config
attr_accessor :run_highstate
attr_accessor :run_overstate
attr_accessor :always_install
@@ -38,6 +39,7 @@ module VagrantPlugins
@master_config = UNSET_VALUE
@master_key = UNSET_VALUE
@master_pub = UNSET_VALUE
+ @grains_config = UNSET_VALUE
@run_highstate = UNSET_VALUE
@run_overstate = UNSET_VALUE
@always_install = UNSET_VALUE
@@ -63,6 +65,7 @@ module VagrantPlugins
@master_config = nil if @master_config == UNSET_VALUE
@master_key = nil if @master_key == UNSET_VALUE
@master_pub = nil if @master_pub == UNSET_VALUE
+ @grains_config = nil if @grains_config == UNSET_VALUE
@run_highstate = nil if @run_highstate == UNSET_VALUE
@run_overstate = nil if @run_overstate == UNSET_VALUE
@always_install = nil if @always_install == UNSET_VALUE
@@ -115,6 +118,13 @@ module VagrantPlugins
end
end
+ if @grains_config
+ expanded = Pathname.new(@grains_config).expand_path(machine.env.root_path)
+ if !expanded.file?
+ errors << I18n.t("vagrant.provisioners.salt.grains_config_nonexist")
+ end
+ end
+
if @install_master && !@no_minion && !@seed_master && @run_highstate
errors << I18n.t("vagrant.provisioners.salt.must_accept_keys")
end
diff --git a/plugins/provisioners/salt/provisioner.rb b/plugins/provisioners/salt/provisioner.rb
index c5db597a0..d7596a1ec 100644
--- a/plugins/provisioners/salt/provisioner.rb
+++ b/plugins/provisioners/salt/provisioner.rb
@@ -75,7 +75,7 @@ module VagrantPlugins
end
def need_configure
- @config.minion_config or @config.minion_key or @config.master_config or @config.master_key
+ @config.minion_config or @config.minion_key or @config.master_config or @config.master_key or @config.grains_config
end
def need_install
@@ -181,6 +181,11 @@ module VagrantPlugins
@machine.env.ui.info "Copying salt master config to vm."
@machine.communicate.upload(expanded_path(@config.master_config).to_s, temp_config_dir + "/master")
end
+
+ if @config.grains_config
+ @machine.env.ui.info "Copying salt grains config to vm."
+ @machine.communicate.upload(expanded_path(@config.grains_config).to_s, temp_config_dir + "/grains")
+ end
end
# Copy master and minion keys to VM
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index 72124f7e9..f475f8296 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -1888,6 +1888,8 @@ en:
The specified minion_config file could not be found.
master_config_nonexist: |-
The specified master_config file could not be found.
+ grains_config_nonexist: |-
+ The specified grains_config file could not be found.
missing_key: |-
You must include both public and private keys.
must_accept_keys: |-
diff --git a/test/unit/plugins/provisioners/salt/config_test.rb b/test/unit/plugins/provisioners/salt/config_test.rb
index c640a7497..24bf24796 100644
--- a/test/unit/plugins/provisioners/salt/config_test.rb
+++ b/test/unit/plugins/provisioners/salt/config_test.rb
@@ -60,5 +60,23 @@ describe VagrantPlugins::Salt::Config do
expect(result[error_key]).to be_empty
end
end
+
+ context "grains_config" do
+ it "fails if grains_config is set and missing" do
+ subject.grains_config = "/nope/still/not/here"
+ subject.finalize!
+
+ result = subject.validate(machine)
+ expect(result[error_key]).to_not be_empty
+ end
+
+ it "is valid if is set and not missing" do
+ subject.grains_config = File.expand_path(__FILE__)
+ subject.finalize!
+
+ result = subject.validate(machine)
+ expect(result[error_key]).to be_empty
+ end
+ end
end
end
diff --git a/website/docs/source/v2/provisioning/salt.html.md b/website/docs/source/v2/provisioning/salt.html.md
index f66ac7c60..ddc81fa90 100644
--- a/website/docs/source/v2/provisioning/salt.html.md
+++ b/website/docs/source/v2/provisioning/salt.html.md
@@ -56,7 +56,7 @@ on this machine. Not supported on Windows.
`false`. Not supported on Windows.
* `install_type` (stable | git | daily | testing) - Whether to install from a
-distribution's stable package manager, git tree-ish, daily ppa, or testing repository.
+distribution's stable package manager, git tree-ish, daily ppa, or testing repository.
Not supported on Windows.
* `install_args` (develop) - When performing a git install,
@@ -77,6 +77,7 @@ a custom salt minion config file.
* `minion_pub` (salt/key/minion.pub) - Path to your minion
public key
+* `grains_config` (string) - Path to a custom salt grains file.
## Master Options
These only make sense when `install_master` is `true`.
From c6cce57ff46fdb5145124c260894c3517c5eb0f0 Mon Sep 17 00:00:00 2001
From: Jeff Quast
Date: Wed, 3 Dec 2014 21:48:30 -0800
Subject: [PATCH 008/203] Avoid double-newlines in salt-call output
When using the salt provisioner with verbose=true, most lines read with an extra newline:
```
[INFO ] Syncing modules for environment 'base'
[INFO ] Loading cache from salt://_modules, for base)
```
because the line read has a newline, and emitting the log entry again includes an additional newline.
---
plugins/provisioners/salt/provisioner.rb | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/provisioners/salt/provisioner.rb b/plugins/provisioners/salt/provisioner.rb
index c5db597a0..a47bce2a6 100644
--- a/plugins/provisioners/salt/provisioner.rb
+++ b/plugins/provisioners/salt/provisioner.rb
@@ -306,7 +306,7 @@ module VagrantPlugins
@machine.communicate.sudo("salt '*' saltutil.sync_all")
@machine.communicate.sudo("salt '*' state.highstate --verbose#{get_loglevel}#{get_colorize}#{get_pillar}") do |type, data|
if @config.verbose
- @machine.env.ui.info(data)
+ @machine.env.ui.info(data.rstrip)
end
end
else
@@ -315,14 +315,14 @@ module VagrantPlugins
@machine.communicate.execute("C:\\salt\\salt-call.exe saltutil.sync_all", opts)
@machine.communicate.execute("C:\\salt\\salt-call.exe state.highstate --retcode-passthrough #{get_loglevel}#{get_colorize}#{get_pillar}", opts) do |type, data|
if @config.verbose
- @machine.env.ui.info(data)
+ @machine.env.ui.info(data.rstrip)
end
end
else
@machine.communicate.sudo("salt-call saltutil.sync_all")
@machine.communicate.sudo("salt-call state.highstate --retcode-passthrough #{get_loglevel}#{get_colorize}#{get_pillar}") do |type, data|
if @config.verbose
- @machine.env.ui.info(data)
+ @machine.env.ui.info(data.rstrip)
end
end
end
From 86ab6880c27152ae17929c5040f31118e163492c Mon Sep 17 00:00:00 2001
From: Riccardo Attilio Galli
Date: Thu, 4 Dec 2014 16:09:04 +0100
Subject: [PATCH 009/203] New default option of rsync "--copy-links"
As can be seen in [rsync/helper.rb](https://github.com/mitchellh/vagrant/blob/efd1d5e11bfc5a72c7a1d1eae294b4751d841544/plugins/synced_folders/rsync/helper.rb#L81) the "--copy-links" option has been added to the defaults.
---
website/docs/source/v2/synced-folders/rsync.html.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/website/docs/source/v2/synced-folders/rsync.html.md b/website/docs/source/v2/synced-folders/rsync.html.md
index 62e88d0dd..bfa322850 100644
--- a/website/docs/source/v2/synced-folders/rsync.html.md
+++ b/website/docs/source/v2/synced-folders/rsync.html.md
@@ -44,7 +44,7 @@ the destination folder.
The rsync synced folder type accepts the following options:
* `rsync__args` (array of strings) - A list of arguments to supply
- to `rsync`. By default this is `["--verbose", "--archive", "--delete", "-z"]`.
+ to `rsync`. By default this is `["--verbose", "--archive", "--delete", "-z", "--copy-links"]`.
* `rsync__auto` (boolean) - If false, then `rsync-auto` will not
watch and automatically sync this folder. By default, this is true.
From 40a22ff99a2fd46b3a2a6e7f574b9bf75210c974 Mon Sep 17 00:00:00 2001
From: Gilles Cornu
Date: Sun, 7 Dec 2014 11:02:50 +0100
Subject: [PATCH 010/203] providers/docker: fix support of agent forwarding
---
.../providers/docker/action/prepare_ssh.rb | 7 ++++++-
plugins/providers/docker/communicator.rb | 21 +++++++++++--------
2 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/plugins/providers/docker/action/prepare_ssh.rb b/plugins/providers/docker/action/prepare_ssh.rb
index 1a7298a66..450b139c6 100644
--- a/plugins/providers/docker/action/prepare_ssh.rb
+++ b/plugins/providers/docker/action/prepare_ssh.rb
@@ -19,14 +19,19 @@ module VagrantPlugins
# Modify the SSH options for when we `vagrant ssh`...
ssh_opts = env[:ssh_opts] || {}
- # Build the command we'll execute within the host machine
+ # Build the command we'll execute within the Docker host machine:
ssh_command = env[:machine].communicate.container_ssh_command
if !Array(ssh_opts[:extra_args]).empty?
ssh_command << " #{Array(ssh_opts[:extra_args]).join(" ")}"
end
+ # Modify the SSH options for the original command:
# Append "-t" to force a TTY allocation
ssh_opts[:extra_args] = ["-t"]
+ # Enable Agent forwarding when requested for the target VM
+ if env[:machine].ssh_info[:forward_agent]
+ ssh_opts[:extra_args] << "-o ForwardAgent=yes"
+ end
ssh_opts[:extra_args] << ssh_command
# Set the opts
diff --git a/plugins/providers/docker/communicator.rb b/plugins/providers/docker/communicator.rb
index 657789575..fb6c9fe9e 100644
--- a/plugins/providers/docker/communicator.rb
+++ b/plugins/providers/docker/communicator.rb
@@ -137,18 +137,21 @@ module VagrantPlugins
info[:port] ||= 22
# Make sure our private keys are synced over to the host VM
- key_args = sync_private_keys(info).map do |path|
+ ssh_args = sync_private_keys(info).map do |path|
"-i #{path}"
- end.join(" ")
+ end
+
+ # Use ad-hoc SSH options for the hop on the docker proxy
+ if info[:forward_agent]
+ ssh_args << "-o ForwardAgent=yes"
+ end
+ ssh_args.concat(["-o Compression=yes",
+ "-o ConnectTimeout=5",
+ "-o StrictHostKeyChecking=no",
+ "-o UserKnownHostsFile=/dev/null"])
# Build the SSH command
- "ssh #{key_args} " +
- "-o Compression=yes " +
- "-o ConnectTimeout=5 " +
- "-o StrictHostKeyChecking=no " +
- "-o UserKnownHostsFile=/dev/null " +
- "-p#{info[:port]} " +
- "#{info[:username]}@#{info[:host]}"
+ "ssh #{info[:username]}@#{info[:host]} -p#{info[:port]} #{ssh_args.join(" ")}"
end
protected
From 0a64b0c4e18ca9ee0db5def530a09e97ad1feaa0 Mon Sep 17 00:00:00 2001
From: Gilles Cornu
Date: Sun, 7 Dec 2014 11:14:21 +0100
Subject: [PATCH 011/203] Update CHANGELOG: fix docker agent forwarding
Ref GH-4905
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 53565b085..002ad9a86 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -82,6 +82,7 @@ BUG FIXES:
- providers/docker: Fix issue where multiple identical proxy VMs would
be created. [GH-3963]
- providers/docker: Multiple links with the same name work. [GH-4571]
+ - providers/docker: Add support of SSH agent forwarding. [GH-4905]
- providers/virtualbox: Show a human-friendly error if VirtualBox didn't
clean up an existing VM. [GH-4681]
- providers/virtualbox: Detect case when VirtualBox reports 0.0.0.0 as
From 38001032287191e2e425f2327047b2209ab3f927 Mon Sep 17 00:00:00 2001
From: Gilles Cornu
Date: Sun, 7 Dec 2014 22:34:19 +0100
Subject: [PATCH 012/203] provisioners/ansible: improve comment wording
Get rid of the Joker, thanks to @maspwr :)
---
plugins/provisioners/ansible/provisioner.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb
index e403b561f..49015997b 100644
--- a/plugins/provisioners/ansible/provisioner.rb
+++ b/plugins/provisioners/ansible/provisioner.rb
@@ -43,8 +43,8 @@ module VagrantPlugins
options << "--skip-tags=#{as_list_argument(config.skip_tags)}" if config.skip_tags
options << "--start-at-task=#{config.start_at_task}" if config.start_at_task
- # Finally, add the configuration joker, which has the highest precedence and
- # can therefore potentially override any other options of this provisioner.
+ # Finally, add the raw configuration options, which has the highest precedence
+ # and can therefore potentially override any other options of this provisioner.
options.concat(self.as_array(config.raw_arguments)) if config.raw_arguments
#
From 9e9362d9760fb5054aec2847bac0fa69205fa88b Mon Sep 17 00:00:00 2001
From: Atha Kouroussis
Date: Mon, 8 Dec 2014 09:42:13 -0500
Subject: [PATCH 013/203] Fix broken rsync cap for Solaris guests
---
plugins/guests/solaris/cap/rsync.rb | 6 +++---
plugins/guests/solaris11/cap/rsync.rb | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/plugins/guests/solaris/cap/rsync.rb b/plugins/guests/solaris/cap/rsync.rb
index d060a8020..0d0220f40 100644
--- a/plugins/guests/solaris/cap/rsync.rb
+++ b/plugins/guests/solaris/cap/rsync.rb
@@ -17,10 +17,10 @@ module VagrantPlugins
end
def self.rsync_post(machine, opts)
- su_cmd = machine.config.solaris.su_cmd
+ suexec_cmd = machine.config.solaris.suexec_cmd
machine.communicate.execute(
- "#{su_cmd} find '#{opts[:guestpath]}' '(' ! -user #{opts[:owner]} -or ! -group #{opts[:group]} ')' -print0 | " +
- "xargs -0 -r chown #{opts[:owner]}:#{opts[:group]}")
+ "#{suexec_cmd} find '#{opts[:guestpath]}' '(' ! -user #{opts[:owner]} -or ! -group #{opts[:group]} ')' -print0 | " +
+ "xargs -0 chown #{opts[:owner]}:#{opts[:group]}")
end
end
end
diff --git a/plugins/guests/solaris11/cap/rsync.rb b/plugins/guests/solaris11/cap/rsync.rb
index 039602172..95df046c9 100644
--- a/plugins/guests/solaris11/cap/rsync.rb
+++ b/plugins/guests/solaris11/cap/rsync.rb
@@ -17,10 +17,10 @@ module VagrantPlugins
end
def self.rsync_post(machine, opts)
- su_cmd = machine.config.solaris11.su_cmd
+ suexec_cmd = machine.config.solaris11.suexec_cmd
machine.communicate.execute(
- "#{su_cmd} '#{opts[:guestpath]}' '(' ! -user #{opts[:owner]} -or ! -group #{opts[:group]} ')' -print0 | " +
- "xargs -0 -r chown #{opts[:owner]}:#{opts[:group]}")
+ "#{suexec_cmd} '#{opts[:guestpath]}' '(' ! -user #{opts[:owner]} -or ! -group #{opts[:group]} ')' -print0 | " +
+ "xargs -0 chown #{opts[:owner]}:#{opts[:group]}")
end
end
end
From a93fff103f90cdad7f12eb2af129ffb8cde93434 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 22 Oct 2014 17:39:45 -0400
Subject: [PATCH 014/203] Add base skeleton for `vagrant push`
---
lib/vagrant/plugin/v2.rb | 1 +
lib/vagrant/plugin/v2/plugin.rb | 13 +++++++++++++
lib/vagrant/plugin/v2/push.rb | 31 +++++++++++++++++++++++++++++++
3 files changed, 45 insertions(+)
create mode 100644 lib/vagrant/plugin/v2/push.rb
diff --git a/lib/vagrant/plugin/v2.rb b/lib/vagrant/plugin/v2.rb
index 1539667bd..953f73ff6 100644
--- a/lib/vagrant/plugin/v2.rb
+++ b/lib/vagrant/plugin/v2.rb
@@ -16,6 +16,7 @@ module Vagrant
autoload :Manager, "vagrant/plugin/v2/manager"
autoload :Plugin, "vagrant/plugin/v2/plugin"
autoload :Provider, "vagrant/plugin/v2/provider"
+ autoload :Push, "vagrant/plugin/v2/push"
autoload :Provisioner, "vagrant/plugin/v2/provisioner"
autoload :SyncedFolder, "vagrant/plugin/v2/synced_folder"
end
diff --git a/lib/vagrant/plugin/v2/plugin.rb b/lib/vagrant/plugin/v2/plugin.rb
index 9a7f6177d..e6020f6c5 100644
--- a/lib/vagrant/plugin/v2/plugin.rb
+++ b/lib/vagrant/plugin/v2/plugin.rb
@@ -221,6 +221,19 @@ module Vagrant
data[:provisioners]
end
+ # Registers additional pushes to be available.
+ #
+ # @param [String] name Name of the push.
+ def self.push(name=UNSET_VALUE, &block)
+ data[:pushes] ||= Registry.new
+
+ # Register a new pusher class only if a name was given
+ data[:pushes].register(name.to_sym, &block) if name != UNSET_VALUE
+
+ # Return the registry
+ data[:pushes]
+ end
+
# Registers additional synced folder implementations.
#
# @param [String] name Name of the implementation.
diff --git a/lib/vagrant/plugin/v2/push.rb b/lib/vagrant/plugin/v2/push.rb
new file mode 100644
index 000000000..63f9d4ae0
--- /dev/null
+++ b/lib/vagrant/plugin/v2/push.rb
@@ -0,0 +1,31 @@
+module Vagrant
+ module Plugin
+ module V2
+ class Push
+ attr_reader :machine
+ attr_reader :config
+
+ # Initializes the pusher with the machine that exists for this project
+ # as well as the configuration (the push configuration, not the full machine
+ # configuration).
+ #
+ # The pusher should _not_ do anything at this point except
+ # initialize internal state.
+ #
+ # @param [Machine] machine The machine associated with this code.
+ # @param [Object] config Push configuration, if one was set.
+ def initialize(machine, config)
+ @machine = machine
+ @config = config
+ end
+
+ # This is the method called when the actual pushing should be
+ # done.
+ #
+ # No return value is expected.
+ def push
+ end
+ end
+ end
+ end
+end
From 8a7e546972bb0b613804edc16f3e6914d6b803c5 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 22 Oct 2014 17:40:08 -0400
Subject: [PATCH 015/203] Add preliminary File pusher (incomplete)
---
plugins/pushes/file/config.rb | 26 +++++++++++++++
plugins/pushes/file/plugin.rb | 23 +++++++++++++
plugins/pushes/file/push.rb | 29 +++++++++++++++++
templates/locales/en.yml | 4 +++
test/unit/plugins/pushes/file/config_test.rb | 34 ++++++++++++++++++++
5 files changed, 116 insertions(+)
create mode 100644 plugins/pushes/file/config.rb
create mode 100644 plugins/pushes/file/plugin.rb
create mode 100644 plugins/pushes/file/push.rb
create mode 100644 test/unit/plugins/pushes/file/config_test.rb
diff --git a/plugins/pushes/file/config.rb b/plugins/pushes/file/config.rb
new file mode 100644
index 000000000..025ab78dd
--- /dev/null
+++ b/plugins/pushes/file/config.rb
@@ -0,0 +1,26 @@
+module VagrantPlugins
+ module FileDeploy
+ class Config < Vagrant.plugin("2", :config)
+ attr_accessor :destination
+
+ def initialize
+ @destination = UNSET_VALUE
+ end
+
+ def finalize!
+ @destination = nil if @destination == UNSET_VALUE
+ end
+
+ def validate(machine)
+ errors = _detected_errors
+
+ # Validate that a destination was provided
+ if !destination
+ errors << I18n.t("vagrant.pushes.file.no_destination")
+ end
+
+ { "File push" => errors }
+ end
+ end
+ end
+end
diff --git a/plugins/pushes/file/plugin.rb b/plugins/pushes/file/plugin.rb
new file mode 100644
index 000000000..365e5e44c
--- /dev/null
+++ b/plugins/pushes/file/plugin.rb
@@ -0,0 +1,23 @@
+require "vagrant"
+
+module VagrantPlugins
+ module FileDeploy
+ class Plugin < Vagrant.plugin("2")
+ name "file"
+ description <<-DESC
+ Deploy by pushing to a filepath on your local system or a remote share
+ attached to this system
+ DESC
+
+ config(:file, :push) do
+ require File.expand_path("../config", __FILE__)
+ Config
+ end
+
+ push(:file) do
+ require File.expand_path("../push", __FILE__)
+ Push
+ end
+ end
+ end
+end
diff --git a/plugins/pushes/file/push.rb b/plugins/pushes/file/push.rb
new file mode 100644
index 000000000..662719ec5
--- /dev/null
+++ b/plugins/pushes/file/push.rb
@@ -0,0 +1,29 @@
+module VagrantPlugins
+ module FileDeploy
+ class Push < Vagrant.plugin("2", :push)
+ def push
+ @machine.communicate.tap do |comm|
+ destination = expand_guest_path(config.destination)
+
+ # Make sure the remote path exists
+ command = "mkdir -p %s" % File.dirname(destination)
+ comm.execute(command)
+
+ # Now push the deploy...
+ # ???
+ end
+ end
+
+ private
+
+ # Expand the guest path if the guest has the capability
+ def expand_guest_path(destination)
+ if machine.guest.capability?(:shell_expand_guest_path)
+ machine.guest.capability(:shell_expand_guest_path, destination)
+ else
+ destination
+ end
+ end
+ end
+ end
+end
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index 72124f7e9..bc3416529 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -1892,3 +1892,7 @@ en:
You must include both public and private keys.
must_accept_keys: |-
You must accept keys when running highstate with master!
+
+ pushes:
+ file:
+ no_destination: "File destination must be specified."
diff --git a/test/unit/plugins/pushes/file/config_test.rb b/test/unit/plugins/pushes/file/config_test.rb
new file mode 100644
index 000000000..c5c7c591e
--- /dev/null
+++ b/test/unit/plugins/pushes/file/config_test.rb
@@ -0,0 +1,34 @@
+require_relative "../../../base"
+
+require Vagrant.source_root.join("plugins/pushes/file/config")
+
+describe VagrantPlugins::FileDeploy::Config do
+ include_context "unit"
+
+ subject { described_class.new }
+
+ let(:machine) { double("machine") }
+
+ describe "#validate" do
+ it "returns an error if destination is not specified" do
+ subject.finalize!
+
+ result = subject.validate(machine)
+
+ expect(result["File push"]).to eql([
+ I18n.t("vagrant.pushes.file.no_destination")
+ ])
+ end
+
+ it "returns no errors when the config is valid" do
+ existing_file = File.expand_path(__FILE__)
+
+ subject.destination = existing_file
+ subject.finalize!
+
+ result = subject.validate(machine)
+
+ expect(result["File push"]).to be_empty
+ end
+ end
+end
From 87b4e1f2ccc45fac688dfe3dd3248f087c59216e Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 22 Oct 2014 22:02:46 -0400
Subject: [PATCH 016/203] Accept an environment in the push config
---
lib/vagrant/plugin/v2/push.rb | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/lib/vagrant/plugin/v2/push.rb b/lib/vagrant/plugin/v2/push.rb
index 63f9d4ae0..002479b33 100644
--- a/lib/vagrant/plugin/v2/push.rb
+++ b/lib/vagrant/plugin/v2/push.rb
@@ -2,20 +2,16 @@ module Vagrant
module Plugin
module V2
class Push
- attr_reader :machine
+ attr_reader :environment
attr_reader :config
- # Initializes the pusher with the machine that exists for this project
- # as well as the configuration (the push configuration, not the full machine
- # configuration).
+ # Initializes the pusher with the given environment the push
+ # configuration.
#
- # The pusher should _not_ do anything at this point except
- # initialize internal state.
- #
- # @param [Machine] machine The machine associated with this code.
- # @param [Object] config Push configuration, if one was set.
- def initialize(machine, config)
- @machine = machine
+ # @param [environment] environment
+ # @param [Object] config Push configuration
+ def initialize(environment, config)
+ @environment = environment
@config = config
end
From 5b9240ad8a52e1c70638a28a4431f1dc65d1e4ee Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 22 Oct 2014 22:02:57 -0400
Subject: [PATCH 017/203] Add Push to the PLUGIN_COMPONENTS
---
lib/vagrant.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/vagrant.rb b/lib/vagrant.rb
index d3ab6f37c..4b5dc84ba 100644
--- a/lib/vagrant.rb
+++ b/lib/vagrant.rb
@@ -123,6 +123,7 @@ module Vagrant
c.register([:"2", :host]) { Plugin::V2::Host }
c.register([:"2", :provider]) { Plugin::V2::Provider }
c.register([:"2", :provisioner]) { Plugin::V2::Provisioner }
+ c.register([:"2", :push]) { Plugin::V2::Push }
c.register([:"2", :synced_folder]) { Plugin::V2::SyncedFolder }
end
From 72affa0a10ba65edc27a4c48212a1183fd3ce7db Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 22 Oct 2014 22:03:11 -0400
Subject: [PATCH 018/203] Accept a list of options in #push signature
---
lib/vagrant/plugin/v2/plugin.rb | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/vagrant/plugin/v2/plugin.rb b/lib/vagrant/plugin/v2/plugin.rb
index e6020f6c5..9b09d94b0 100644
--- a/lib/vagrant/plugin/v2/plugin.rb
+++ b/lib/vagrant/plugin/v2/plugin.rb
@@ -224,11 +224,13 @@ module Vagrant
# Registers additional pushes to be available.
#
# @param [String] name Name of the push.
- def self.push(name=UNSET_VALUE, &block)
+ def self.push(name=UNSET_VALUE, options=nil, &block)
data[:pushes] ||= Registry.new
# Register a new pusher class only if a name was given
- data[:pushes].register(name.to_sym, &block) if name != UNSET_VALUE
+ if name != UNSET_VALUE
+ data[:pushes].register(name.to_sym) { [block.call, options] }
+ end
# Return the registry
data[:pushes]
From 0e824cc47193047ad389226b1c8c3f5ca53343d9 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 22 Oct 2014 22:29:23 -0400
Subject: [PATCH 019/203] Rename file push to noop push
---
plugins/pushes/file/config.rb | 26 ---------------
plugins/pushes/file/push.rb | 29 -----------------
plugins/pushes/noop/config.rb | 16 +++++++++
plugins/pushes/{file => noop}/plugin.rb | 11 +++----
plugins/pushes/noop/push.rb | 11 +++++++
test/unit/plugins/pushes/file/config_test.rb | 34 --------------------
test/unit/plugins/pushes/noop/config_test.rb | 14 ++++++++
7 files changed, 46 insertions(+), 95 deletions(-)
delete mode 100644 plugins/pushes/file/config.rb
delete mode 100644 plugins/pushes/file/push.rb
create mode 100644 plugins/pushes/noop/config.rb
rename plugins/pushes/{file => noop}/plugin.rb (60%)
create mode 100644 plugins/pushes/noop/push.rb
delete mode 100644 test/unit/plugins/pushes/file/config_test.rb
create mode 100644 test/unit/plugins/pushes/noop/config_test.rb
diff --git a/plugins/pushes/file/config.rb b/plugins/pushes/file/config.rb
deleted file mode 100644
index 025ab78dd..000000000
--- a/plugins/pushes/file/config.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-module VagrantPlugins
- module FileDeploy
- class Config < Vagrant.plugin("2", :config)
- attr_accessor :destination
-
- def initialize
- @destination = UNSET_VALUE
- end
-
- def finalize!
- @destination = nil if @destination == UNSET_VALUE
- end
-
- def validate(machine)
- errors = _detected_errors
-
- # Validate that a destination was provided
- if !destination
- errors << I18n.t("vagrant.pushes.file.no_destination")
- end
-
- { "File push" => errors }
- end
- end
- end
-end
diff --git a/plugins/pushes/file/push.rb b/plugins/pushes/file/push.rb
deleted file mode 100644
index 662719ec5..000000000
--- a/plugins/pushes/file/push.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-module VagrantPlugins
- module FileDeploy
- class Push < Vagrant.plugin("2", :push)
- def push
- @machine.communicate.tap do |comm|
- destination = expand_guest_path(config.destination)
-
- # Make sure the remote path exists
- command = "mkdir -p %s" % File.dirname(destination)
- comm.execute(command)
-
- # Now push the deploy...
- # ???
- end
- end
-
- private
-
- # Expand the guest path if the guest has the capability
- def expand_guest_path(destination)
- if machine.guest.capability?(:shell_expand_guest_path)
- machine.guest.capability(:shell_expand_guest_path, destination)
- else
- destination
- end
- end
- end
- end
-end
diff --git a/plugins/pushes/noop/config.rb b/plugins/pushes/noop/config.rb
new file mode 100644
index 000000000..9b23fb450
--- /dev/null
+++ b/plugins/pushes/noop/config.rb
@@ -0,0 +1,16 @@
+module VagrantPlugins
+ module NoopDeploy
+ class Config < Vagrant.plugin("2", :config)
+ def initialize
+ end
+
+ def finalize!
+ end
+
+ def validate(machine)
+ errors = _detected_errors
+ { "Noop push" => errors }
+ end
+ end
+ end
+end
diff --git a/plugins/pushes/file/plugin.rb b/plugins/pushes/noop/plugin.rb
similarity index 60%
rename from plugins/pushes/file/plugin.rb
rename to plugins/pushes/noop/plugin.rb
index 365e5e44c..d3dc6994d 100644
--- a/plugins/pushes/file/plugin.rb
+++ b/plugins/pushes/noop/plugin.rb
@@ -1,20 +1,19 @@
require "vagrant"
module VagrantPlugins
- module FileDeploy
+ module NoopDeploy
class Plugin < Vagrant.plugin("2")
- name "file"
+ name "noop"
description <<-DESC
- Deploy by pushing to a filepath on your local system or a remote share
- attached to this system
+ Literally do nothing
DESC
- config(:file, :push) do
+ config(:noop, :push) do
require File.expand_path("../config", __FILE__)
Config
end
- push(:file) do
+ push(:noop) do
require File.expand_path("../push", __FILE__)
Push
end
diff --git a/plugins/pushes/noop/push.rb b/plugins/pushes/noop/push.rb
new file mode 100644
index 000000000..490e32188
--- /dev/null
+++ b/plugins/pushes/noop/push.rb
@@ -0,0 +1,11 @@
+module VagrantPlugins
+ module NoopDeploy
+ class Push < Vagrant.plugin("2", :push)
+ def push
+ @machine.communicate.tap do |comm|
+ puts "pushed"
+ end
+ end
+ end
+ end
+end
diff --git a/test/unit/plugins/pushes/file/config_test.rb b/test/unit/plugins/pushes/file/config_test.rb
deleted file mode 100644
index c5c7c591e..000000000
--- a/test/unit/plugins/pushes/file/config_test.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require_relative "../../../base"
-
-require Vagrant.source_root.join("plugins/pushes/file/config")
-
-describe VagrantPlugins::FileDeploy::Config do
- include_context "unit"
-
- subject { described_class.new }
-
- let(:machine) { double("machine") }
-
- describe "#validate" do
- it "returns an error if destination is not specified" do
- subject.finalize!
-
- result = subject.validate(machine)
-
- expect(result["File push"]).to eql([
- I18n.t("vagrant.pushes.file.no_destination")
- ])
- end
-
- it "returns no errors when the config is valid" do
- existing_file = File.expand_path(__FILE__)
-
- subject.destination = existing_file
- subject.finalize!
-
- result = subject.validate(machine)
-
- expect(result["File push"]).to be_empty
- end
- end
-end
diff --git a/test/unit/plugins/pushes/noop/config_test.rb b/test/unit/plugins/pushes/noop/config_test.rb
new file mode 100644
index 000000000..05be6c3f8
--- /dev/null
+++ b/test/unit/plugins/pushes/noop/config_test.rb
@@ -0,0 +1,14 @@
+require_relative "../../../base"
+
+require Vagrant.source_root.join("plugins/pushes/noop/config")
+
+describe VagrantPlugins::NoopDeploy::Config do
+ include_context "unit"
+
+ subject { described_class.new }
+
+ let(:machine) { double("machine") }
+
+ describe "#validate" do
+ end
+end
From 60a847289190075144fff8dd3d842de4a738503c Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 22 Oct 2014 22:29:39 -0400
Subject: [PATCH 020/203] Use a pushes registry instead of data hash
---
lib/vagrant/plugin/v2/components.rb | 6 ++++
lib/vagrant/plugin/v2/plugin.rb | 11 +++----
test/unit/vagrant/plugin/v2/plugin_test.rb | 35 ++++++++++++++++++++++
3 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/lib/vagrant/plugin/v2/components.rb b/lib/vagrant/plugin/v2/components.rb
index 7bae6c29a..d7c64d370 100644
--- a/lib/vagrant/plugin/v2/components.rb
+++ b/lib/vagrant/plugin/v2/components.rb
@@ -54,6 +54,11 @@ module Vagrant
# @return [Hash]
attr_reader :provider_capabilities
+ # This contains all the push implementations by name.
+ #
+ # @return [Registry>]
+ attr_reader :pushes
+
# This contains all the synced folder implementations by name.
#
# @return [Registry>]
@@ -71,6 +76,7 @@ module Vagrant
@host_capabilities = Hash.new { |h, k| h[k] = Registry.new }
@providers = Registry.new
@provider_capabilities = Hash.new { |h, k| h[k] = Registry.new }
+ @pushes = Registry.new
@synced_folders = Registry.new
end
end
diff --git a/lib/vagrant/plugin/v2/plugin.rb b/lib/vagrant/plugin/v2/plugin.rb
index 9b09d94b0..bcae23eaa 100644
--- a/lib/vagrant/plugin/v2/plugin.rb
+++ b/lib/vagrant/plugin/v2/plugin.rb
@@ -224,16 +224,13 @@ module Vagrant
# Registers additional pushes to be available.
#
# @param [String] name Name of the push.
+ # @param [Hash] options List of options for the push.
def self.push(name=UNSET_VALUE, options=nil, &block)
- data[:pushes] ||= Registry.new
-
- # Register a new pusher class only if a name was given
- if name != UNSET_VALUE
- data[:pushes].register(name.to_sym) { [block.call, options] }
+ components.pushes.register(name.to_sym) do
+ [block.call, options]
end
- # Return the registry
- data[:pushes]
+ nil
end
# Registers additional synced folder implementations.
diff --git a/test/unit/vagrant/plugin/v2/plugin_test.rb b/test/unit/vagrant/plugin/v2/plugin_test.rb
index 944d38f9f..442462805 100644
--- a/test/unit/vagrant/plugin/v2/plugin_test.rb
+++ b/test/unit/vagrant/plugin/v2/plugin_test.rb
@@ -322,6 +322,41 @@ describe Vagrant::Plugin::V2::Plugin do
end
end
+ describe "pushes" do
+ it "should register implementations" do
+ plugin = Class.new(described_class) do
+ push("foo") { "bar" }
+ end
+
+ expect(plugin.components.pushes[:foo]).to eq(["bar", nil])
+ end
+
+ it "should be able to specify priorities" do
+ plugin = Class.new(described_class) do
+ push("foo", bar: 1) { "bar" }
+ end
+
+ expect(plugin.components.pushes[:foo]).to eq(["bar", bar: 1])
+ end
+
+ it "should lazily register implementations" do
+ # Below would raise an error if the value of the config class was
+ # evaluated immediately. By asserting that this does not raise an
+ # error, we verify that the value is actually lazily loaded
+ plugin = nil
+ expect {
+ plugin = Class.new(described_class) do
+ push("foo") { raise StandardError, "FAIL!" }
+ end
+ }.to_not raise_error
+
+ # Now verify when we actually get the configuration key that
+ # a proper error is raised.
+ expect {
+ plugin.components.pushes[:foo]
+ }.to raise_error(StandardError)
+ end
+ end
describe "synced folders" do
it "should register implementations" do
plugin = Class.new(described_class) do
From bc4bbb9fc0973b1efc59cf95d60bd1521815133e Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 23 Oct 2014 11:17:23 -0400
Subject: [PATCH 021/203] Add #length and #size methods to Registry
---
lib/vagrant/registry.rb | 10 +++++++++-
test/unit/vagrant/registry_test.rb | 22 ++++++++++++++++++++++
2 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/lib/vagrant/registry.rb b/lib/vagrant/registry.rb
index 5095f2097..f26e17d4f 100644
--- a/lib/vagrant/registry.rb
+++ b/lib/vagrant/registry.rb
@@ -34,7 +34,7 @@ module Vagrant
def has_key?(key)
@items.has_key?(key)
end
-
+
# Returns an array populated with the keys of this object.
#
# @return [Array]
@@ -49,6 +49,14 @@ module Vagrant
end
end
+ # Return the number of elements in this registry.
+ #
+ # @return [Fixnum]
+ def length
+ @items.keys.length
+ end
+ alias_method :size, :length
+
# Merge one registry with another and return a completely new
# registry. Note that the result cache is completely busted, so
# any gets on the new registry will result in a cache miss.
diff --git a/test/unit/vagrant/registry_test.rb b/test/unit/vagrant/registry_test.rb
index d12f46ffe..3a33e9634 100644
--- a/test/unit/vagrant/registry_test.rb
+++ b/test/unit/vagrant/registry_test.rb
@@ -90,6 +90,28 @@ describe Vagrant::Registry do
expect(result["bar"]).to eq("barvalue")
end
+ describe "#length" do
+ it "should return 0 when the registry is empty" do
+ expect(instance.length).to eq(0)
+ end
+
+ it "should return the number of items in the registry" do
+ instance.register("foo") { }
+ instance.register("bar") { }
+
+ expect(instance.length).to eq(2)
+ end
+ end
+
+ describe "#size" do
+ it "should be an alias to #length" do
+ size = described_class.instance_method(:size)
+ length = described_class.instance_method(:length)
+
+ expect(size).to eq(length)
+ end
+ end
+
describe "merging" do
it "should merge in another registry" do
one = described_class.new
From 2b03838fba4fb5be296c81af869f0572bfccdcc2 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 23 Oct 2014 11:23:55 -0400
Subject: [PATCH 022/203] Make Registry enumerable
Registry already responds to #each, so including the Enumerable module
gives us nice methods like #select and #collect fo' free!
---
lib/vagrant/registry.rb | 2 ++
test/unit/vagrant/registry_test.rb | 4 ++++
2 files changed, 6 insertions(+)
diff --git a/lib/vagrant/registry.rb b/lib/vagrant/registry.rb
index f26e17d4f..4e401777b 100644
--- a/lib/vagrant/registry.rb
+++ b/lib/vagrant/registry.rb
@@ -4,6 +4,8 @@ module Vagrant
# This allows certain components (such as guest systems, configuration
# pieces, etc.) to be registered and queried, lazily.
class Registry
+ include Enumerable
+
def initialize
@items = {}
@results_cache = {}
diff --git a/test/unit/vagrant/registry_test.rb b/test/unit/vagrant/registry_test.rb
index 3a33e9634..94364404c 100644
--- a/test/unit/vagrant/registry_test.rb
+++ b/test/unit/vagrant/registry_test.rb
@@ -3,6 +3,10 @@ require File.expand_path("../../base", __FILE__)
describe Vagrant::Registry do
let(:instance) { described_class.new }
+ it "should include enumerable" do
+ expect(instance).to be_a(Enumerable)
+ end
+
it "should return nil for nonexistent items" do
expect(instance.get("foo")).to be_nil
end
From c0b107ff6975b3f181dd9e3d8dbcb1e900c3336d Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 23 Oct 2014 11:24:13 -0400
Subject: [PATCH 023/203] Add Registry#empty? to check if a registry has any
items
---
lib/vagrant/registry.rb | 7 +++++++
test/unit/vagrant/registry_test.rb | 11 +++++++++++
2 files changed, 18 insertions(+)
diff --git a/lib/vagrant/registry.rb b/lib/vagrant/registry.rb
index 4e401777b..bb8521f74 100644
--- a/lib/vagrant/registry.rb
+++ b/lib/vagrant/registry.rb
@@ -59,6 +59,13 @@ module Vagrant
end
alias_method :size, :length
+ # Checks if this registry has any items.
+ #
+ # @return [Boolean]
+ def empty?
+ @items.keys.empty?
+ end
+
# Merge one registry with another and return a completely new
# registry. Note that the result cache is completely busted, so
# any gets on the new registry will result in a cache miss.
diff --git a/test/unit/vagrant/registry_test.rb b/test/unit/vagrant/registry_test.rb
index 94364404c..12ccbec5c 100644
--- a/test/unit/vagrant/registry_test.rb
+++ b/test/unit/vagrant/registry_test.rb
@@ -116,6 +116,17 @@ describe Vagrant::Registry do
end
end
+ describe "#empty" do
+ it "should return true when the registry is empty" do
+ expect(instance.empty?).to be(true)
+ end
+
+ it "should return false when there is at least one element" do
+ instance.register("foo") { }
+ expect(instance.empty?).to be(false)
+ end
+ end
+
describe "merging" do
it "should merge in another registry" do
one = described_class.new
From d79a0d52ddcf19074155ebedeca804811653fa38 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 23 Oct 2014 13:42:02 -0400
Subject: [PATCH 024/203] Do not use Enumerable in Registry
Calling methods like #first in Registry is misleading because it returns
a different result than registry.get(registry.keys.first).
---
lib/vagrant/registry.rb | 2 --
test/unit/vagrant/registry_test.rb | 4 ----
2 files changed, 6 deletions(-)
diff --git a/lib/vagrant/registry.rb b/lib/vagrant/registry.rb
index bb8521f74..f3c86edec 100644
--- a/lib/vagrant/registry.rb
+++ b/lib/vagrant/registry.rb
@@ -4,8 +4,6 @@ module Vagrant
# This allows certain components (such as guest systems, configuration
# pieces, etc.) to be registered and queried, lazily.
class Registry
- include Enumerable
-
def initialize
@items = {}
@results_cache = {}
diff --git a/test/unit/vagrant/registry_test.rb b/test/unit/vagrant/registry_test.rb
index 12ccbec5c..f177a6a1c 100644
--- a/test/unit/vagrant/registry_test.rb
+++ b/test/unit/vagrant/registry_test.rb
@@ -3,10 +3,6 @@ require File.expand_path("../../base", __FILE__)
describe Vagrant::Registry do
let(:instance) { described_class.new }
- it "should include enumerable" do
- expect(instance).to be_a(Enumerable)
- end
-
it "should return nil for nonexistent items" do
expect(instance.get("foo")).to be_nil
end
From b6c5ca6b7ad12f03830c009195eb76f0d78a18e4 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 23 Oct 2014 13:51:18 -0400
Subject: [PATCH 025/203] Add Push command and tests
---
lib/vagrant/errors.rb | 12 ++
lib/vagrant/plugin/v2/manager.rb | 11 ++
plugins/commands/push/command.rb | 64 +++++++++
plugins/commands/push/plugin.rb | 17 +++
templates/locales/en.yml | 17 +++
.../plugins/commands/push/command_test.rb | 129 ++++++++++++++++++
6 files changed, 250 insertions(+)
create mode 100644 plugins/commands/push/command.rb
create mode 100644 plugins/commands/push/plugin.rb
create mode 100644 test/unit/plugins/commands/push/command_test.rb
diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb
index 623073a97..9edbaf194 100644
--- a/lib/vagrant/errors.rb
+++ b/lib/vagrant/errors.rb
@@ -556,6 +556,18 @@ module Vagrant
error_key(:plugin_uninstall_system)
end
+ class PushesNotDefined < VagrantError
+ error_key(:pushes_not_defined)
+ end
+
+ class PushStrategyNotDefined < VagrantError
+ error_key(:push_strategy_not_defined)
+ end
+
+ class PushStrategyNotProvided < VagrantError
+ error_key(:push_strategy_not_provided)
+ end
+
class RSyncError < VagrantError
error_key(:rsync_error)
end
diff --git a/lib/vagrant/plugin/v2/manager.rb b/lib/vagrant/plugin/v2/manager.rb
index 62a23f82a..d8f5296db 100644
--- a/lib/vagrant/plugin/v2/manager.rb
+++ b/lib/vagrant/plugin/v2/manager.rb
@@ -172,6 +172,17 @@ module Vagrant
end
end
+ # This returns all registered pushes.
+ #
+ # @return [Registry]
+ def pushes
+ Registry.new.tap do |result|
+ @registered.each do |plugin|
+ result.merge!(plugin.components.pushes)
+ end
+ end
+ end
+
# This returns all synced folder implementations.
#
# @return [Registry]
diff --git a/plugins/commands/push/command.rb b/plugins/commands/push/command.rb
new file mode 100644
index 000000000..6cbe3452e
--- /dev/null
+++ b/plugins/commands/push/command.rb
@@ -0,0 +1,64 @@
+require 'optparse'
+
+module VagrantPlugins
+ module CommandPush
+ class Command < Vagrant.plugin("2", :command)
+ def self.synopsis
+ "deploys code in this environment to a configured destination"
+ end
+
+ # @todo support multiple strategies if requested by the community
+ def execute
+ opts = OptionParser.new do |o|
+ o.banner = "Usage: vagrant push [strategy] [options]"
+ end
+
+ # Parse the options
+ argv = parse_options(opts)
+ return if !argv
+
+ name, options = argv
+ pushes = @env.pushes
+
+ validate_pushes!(pushes, name)
+
+ @logger.debug("'push' environment with strategy: `#{name}'")
+
+ @env.push(name)
+
+ 0
+ end
+
+ # Validate that the given list of pushes and strategy are valid.
+ #
+ # @raise [PushesNotDefined] if there are no pushes defined for the
+ # environment
+ # @raise [PushStrategyNotDefined] if a strategy is given, but does not
+ # correspond to one that exists in the environment
+ #
+ # @param [Registry] pushes The list of pushes as a {Registry}
+ # @param [#to_sym, nil] name The name of the strategy
+ #
+ # @return [true]
+ def validate_pushes!(pushes, name=nil)
+ if pushes.nil? || pushes.empty?
+ raise Vagrant::Errors::PushesNotDefined
+ end
+
+ if name.nil?
+ if pushes.length != 1
+ raise Vagrant::Errors::PushStrategyNotProvided, pushes: pushes
+ end
+ else
+ if !pushes.has_key?(name.to_sym)
+ raise Vagrant::Errors::PushStrategyNotDefined,
+ name: name,
+ pushes: pushes
+ end
+ end
+
+ true
+ end
+ end
+ end
+end
diff --git a/plugins/commands/push/plugin.rb b/plugins/commands/push/plugin.rb
new file mode 100644
index 000000000..ecd24dd7a
--- /dev/null
+++ b/plugins/commands/push/plugin.rb
@@ -0,0 +1,17 @@
+require "vagrant"
+
+module VagrantPlugins
+ module CommandPush
+ class Plugin < Vagrant.plugin("2")
+ name "push command"
+ description <<-DESC
+ The `push` command deploys code in this environment.
+ DESC
+
+ command("push") do
+ require File.expand_path("../command", __FILE__)
+ Command
+ end
+ end
+ end
+end
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index bc3416529..ce9132fd6 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -946,6 +946,23 @@ en:
You can however, install a plugin with the same name to replace
these plugins. User-installed plugins take priority over
system-installed plugins.
+ pushes_not_defined: |-
+ The Vagrantfile does not define any 'push' strategies. In order to use
+ `vagrant push`, you must define at least one push strategy:
+
+ config.push :ftp do |strategy|
+ # ... strategy-specific options
+ end
+ push_strategy_not_defined: |-
+ The push strategy '%{name}' is not defined in the Vagrantfile. Defined
+ strategies are:
+
+ %{pushes}
+ push_strategy_not_provided: |-
+ The Vagrantfile defines more than one 'push' strategy. Please specify a
+ strategy. Defined strategies are:
+
+ %{pushes}
package_include_symlink: |-
A file or directory you're attempting to include with your packaged
box has symlinks in it. Vagrant cannot include symlinks in the
diff --git a/test/unit/plugins/commands/push/command_test.rb b/test/unit/plugins/commands/push/command_test.rb
new file mode 100644
index 000000000..34bb111ea
--- /dev/null
+++ b/test/unit/plugins/commands/push/command_test.rb
@@ -0,0 +1,129 @@
+require File.expand_path("../../../../base", __FILE__)
+
+require Vagrant.source_root.join("plugins/commands/push/command")
+
+describe VagrantPlugins::CommandPush::Command do
+ include_context "unit"
+ include_context "command plugin helpers"
+
+ def create_registry(items={})
+ Vagrant::Registry.new.tap do |registry|
+ items.each do |k,v|
+ registry.register(k) { v }
+ end
+ end
+ end
+
+ let(:env) do
+ isolated_environment.tap do |env|
+ env.vagrantfile("")
+ env.create_vagrant_env
+ end
+ end
+
+ let(:argv) { [] }
+ let(:pushes) { create_registry }
+
+ subject { described_class.new(argv, env) }
+
+ before do
+ Vagrant.plugin("2").manager.stub(pushes: pushes)
+ end
+
+ describe "#execute" do
+ before do
+ allow(subject).to receive(:validate_pushes!)
+ allow(env).to receive(:pushes)
+ allow(env).to receive(:push)
+ end
+
+ it "validates the pushes" do
+ expect(subject).to receive(:validate_pushes!).once
+ subject.execute
+ end
+
+ it "delegates to Environment#push" do
+ expect(env).to receive(:push).once
+ subject.execute
+ end
+ end
+
+ describe "#validate_pushes!" do
+ context "when there are no pushes defined" do
+ let(:pushes) { create_registry }
+
+ context "when a strategy is given" do
+ it "raises an exception" do
+ expect { subject.validate_pushes!(pushes, :noop) }
+ .to raise_error(Vagrant::Errors::PushesNotDefined)
+ end
+ end
+
+ context "when no strategy is given" do
+ it "raises an exception" do
+ expect { subject.validate_pushes!(pushes) }
+ .to raise_error(Vagrant::Errors::PushesNotDefined)
+ end
+ end
+ end
+
+ context "when there is one push defined" do
+ let(:noop) { double("noop") }
+ let(:pushes) { create_registry(noop: noop) }
+
+ context "when a strategy is given" do
+ context "when that strategy is not defined" do
+ it "raises an exception" do
+ expect { subject.validate_pushes!(pushes, :bacon) }
+ .to raise_error(Vagrant::Errors::PushStrategyNotDefined)
+ end
+ end
+
+ context "when that strategy is defined" do
+ it "does not raise an exception" do
+ expect { subject.validate_pushes!(pushes, :noop) }
+ .to_not raise_error
+ end
+ end
+ end
+
+ context "when no strategy is given" do
+ it "does not raise an exception" do
+ expect { subject.validate_pushes!(pushes) }
+ .to_not raise_error
+ end
+ end
+ end
+
+ context "when there are multiple pushes defined" do
+ let(:noop) { double("noop") }
+ let(:ftp) { double("ftp") }
+ let(:pushes) { create_registry(noop: noop, ftp: ftp) }
+
+ context "when a strategy is given" do
+ context "when that strategy is not defined" do
+ it "raises an exception" do
+ expect { subject.validate_pushes!(pushes, :bacon) }
+ .to raise_error(Vagrant::Errors::PushStrategyNotDefined)
+ end
+ end
+
+ context "when that strategy is defined" do
+ it "does not raise an exception" do
+ expect { subject.validate_pushes!(pushes, :noop) }
+ .to_not raise_error
+ expect { subject.validate_pushes!(pushes, :ftp) }
+ .to_not raise_error
+ end
+ end
+ end
+
+ context "when no strategy is given" do
+ it "raises an exception" do
+ expect { subject.validate_pushes!(pushes) }
+ .to raise_error(Vagrant::Errors::PushStrategyNotProvided)
+ end
+ end
+ end
+ end
+end
From 03b81055710082fd92625bdc8018662a39eb973f Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 23 Oct 2014 16:01:43 -0400
Subject: [PATCH 026/203] Super primitive implementation of Environment#push
---
lib/vagrant/environment.rb | 45 +++++++++
lib/vagrant/errors.rb | 4 +
lib/vagrant/vagrantfile.rb | 14 +++
plugins/commands/push/command.rb | 7 +-
plugins/kernel_v2/config/push.rb | 99 +++++++++++++++++++
plugins/kernel_v2/plugin.rb | 5 +
templates/locales/en.yml | 11 ++-
.../plugins/commands/push/command_test.rb | 16 +--
8 files changed, 184 insertions(+), 17 deletions(-)
create mode 100644 plugins/kernel_v2/config/push.rb
diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb
index 4f087a103..f89c94773 100644
--- a/lib/vagrant/environment.rb
+++ b/lib/vagrant/environment.rb
@@ -539,6 +539,51 @@ module Vagrant
end
end
+ # This executes the push with the given name, raising any exceptions that
+ # occur.
+ #
+ def push(name=nil)
+ @logger.info("Getting push: #{name}")
+
+ if vagrantfile.pushes.nil? || vagrantfile.pushes.empty?
+ raise Vagrant::Errors::PushesNotDefined
+ end
+
+ if name.nil?
+ if vagrantfile.pushes.length != 1
+ raise Vagrant::Errors::PushStrategyNotProvided,
+ pushes: vagrantfile.pushes
+ end
+ name = vagrantfile.pushes.first
+ else
+ if !vagrantfile.pushes.include?(name.to_sym)
+ raise Vagrant::Errors::PushStrategyNotDefined,
+ name: name,
+ pushes: vagrantfile.pushes
+ end
+ end
+
+ push_registry = Vagrant.plugin("2").manager.pushes
+
+ push_config = vagrantfile.push(name)
+ push_config.each do |strategy, config_blocks|
+ plugin, options = push_registry.get(strategy)
+
+ # TODO: What do we do with options?
+ # options
+
+ if plugin.nil?
+ raise Vagrant::Errors::PushStrategyNotLoaded,
+ name: strategy,
+ pushes: push_registry.keys
+ end
+
+ # TODO: This should take a plugin configuration, not a list of config
+ # blocks, or should it?
+ plugin.new(self, config_blocks).push
+ end
+ end
+
# This returns a machine with the proper provider for this environment.
# The machine named by `name` must be in this environment.
#
diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb
index 9edbaf194..de002ffed 100644
--- a/lib/vagrant/errors.rb
+++ b/lib/vagrant/errors.rb
@@ -564,6 +564,10 @@ module Vagrant
error_key(:push_strategy_not_defined)
end
+ class PushStrategyNotLoaded < VagrantError
+ error_key(:push_strategy_not_loaded)
+ end
+
class PushStrategyNotProvided < VagrantError
error_key(:push_strategy_not_provided)
end
diff --git a/lib/vagrant/vagrantfile.rb b/lib/vagrant/vagrantfile.rb
index 011d16351..7467ffbbc 100644
--- a/lib/vagrant/vagrantfile.rb
+++ b/lib/vagrant/vagrantfile.rb
@@ -247,6 +247,20 @@ module Vagrant
nil
end
+ # Returns the list of defined pushes in this Vagrantfile.
+ #
+ # @return [Array]
+ def pushes
+ @config.push.defined_pushes
+ end
+
+ # Get the push by the given name.
+ #
+ # @return [idk]
+ def push(name)
+ @config.push.get_push(name)
+ end
+
protected
def find_vagrantfile(search_path)
diff --git a/plugins/commands/push/command.rb b/plugins/commands/push/command.rb
index 6cbe3452e..ec7324b55 100644
--- a/plugins/commands/push/command.rb
+++ b/plugins/commands/push/command.rb
@@ -17,13 +17,14 @@ module VagrantPlugins
argv = parse_options(opts)
return if !argv
- name, options = argv
+ name = argv[0]
pushes = @env.pushes
+ # TODO: this logic is 100% duplicated in Enviroment#push - should we
+ # just not validate here?
validate_pushes!(pushes, name)
@logger.debug("'push' environment with strategy: `#{name}'")
-
@env.push(name)
0
@@ -50,7 +51,7 @@ module VagrantPlugins
raise Vagrant::Errors::PushStrategyNotProvided, pushes: pushes
end
else
- if !pushes.has_key?(name.to_sym)
+ if !pushes.key?(name.to_sym)
raise Vagrant::Errors::PushStrategyNotDefined,
name: name,
pushes: pushes
diff --git a/plugins/kernel_v2/config/push.rb b/plugins/kernel_v2/config/push.rb
new file mode 100644
index 000000000..c5c3a10b0
--- /dev/null
+++ b/plugins/kernel_v2/config/push.rb
@@ -0,0 +1,99 @@
+require "vagrant"
+
+module VagrantPlugins
+ module Kernel_V2
+ class PushConfig < Vagrant.plugin("2", :config)
+ VALID_OPTIONS = [:strategy].freeze
+
+ attr_accessor :name
+
+ def initialize
+ # Internal state
+ @__defined_pushes = {}
+ @__finalized = false
+ end
+
+ def finalize!
+ @__finalized = true
+ end
+
+ # Define a new push in the Vagrantfile with the given name.
+ #
+ # @example
+ # vm.push.define "ftp"
+ #
+ # @example
+ # vm.push.define "ftp" do |s|
+ # s.host = "..."
+ # end
+ #
+ # @example
+ # vm.push.define "production", strategy: "docker" do |s|
+ # # ...
+ # end
+ #
+ # @param [#to_sym] name The name of the this strategy. By default, this
+ # is also the name of the strategy, but the `:strategy` key can be given
+ # to customize this behavior
+ # @param [Hash] options The list of options
+ #
+ def define(name, **options, &block)
+ validate_options!(options)
+
+ name = name.to_sym
+ strategy = options[:strategy] || name
+
+ @__defined_pushes[name] ||= []
+ @__defined_pushes[name] << [strategy.to_sym, block]
+ end
+
+ # The String representation of this Push.
+ #
+ # @return [String]
+ def to_s
+ "Push"
+ end
+
+ # Custom merge method
+ def merge(other)
+ super.tap do |result|
+ other_pushes = other.instance_variable_get(:@__defined_pushes)
+ new_pushes = @__defined_pushes.dup
+
+ other_pushes.each do |key, tuples|
+ new_pushes[key] ||= []
+ new_pushes[key] += tuples
+ end
+
+ result.instance_variable_set(:@__defined_pushes, new_pushes)
+ end
+ end
+
+ # This returns the list of pushes defined in the Vagrantfile.
+ #
+ # @return [Array]
+ def defined_pushes
+ raise "Must finalize first!" if !@__finalized
+ @__defined_pushes.keys
+ end
+
+ # This returns the compiled push-specific configuration for the given
+ # provider.
+ #
+ # @param [#to_sym] name Name of the push
+ def get_push(name)
+ raise "Must finalize first!" if !@__finalized
+ @__defined_pushes[name.to_sym]
+ end
+
+ private
+
+ def validate_options!(options)
+ extra_keys = VALID_OPTIONS - options.keys
+ if !extra_keys.empty?
+ raise "Invalid option(s): #{extra_keys.join(", ")}"
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/kernel_v2/plugin.rb b/plugins/kernel_v2/plugin.rb
index 0904481df..27737854f 100644
--- a/plugins/kernel_v2/plugin.rb
+++ b/plugins/kernel_v2/plugin.rb
@@ -25,6 +25,11 @@ module VagrantPlugins
PackageConfig
end
+ config("push") do
+ require File.expand_path("../config/push", __FILE__)
+ PushConfig
+ end
+
config("vagrant") do
require File.expand_path("../config/vagrant", __FILE__)
VagrantConfig
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index ce9132fd6..fa3c76414 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -955,12 +955,19 @@ en:
end
push_strategy_not_defined: |-
The push strategy '%{name}' is not defined in the Vagrantfile. Defined
- strategies are:
+ strategy names are:
+
+ %{pushes}
+
+ push_strategy_not_defined: |-
+ There are no push strategies named '%{name}'. Please make sure you
+ spelled it correctly. If you are using an external push strategy, you
+ may need to install a plugin. Loaded push strategies are:
%{pushes}
push_strategy_not_provided: |-
The Vagrantfile defines more than one 'push' strategy. Please specify a
- strategy. Defined strategies are:
+ strategy. Defined strategy names are:
%{pushes}
package_include_symlink: |-
diff --git a/test/unit/plugins/commands/push/command_test.rb b/test/unit/plugins/commands/push/command_test.rb
index 34bb111ea..85be81766 100644
--- a/test/unit/plugins/commands/push/command_test.rb
+++ b/test/unit/plugins/commands/push/command_test.rb
@@ -6,14 +6,6 @@ describe VagrantPlugins::CommandPush::Command do
include_context "unit"
include_context "command plugin helpers"
- def create_registry(items={})
- Vagrant::Registry.new.tap do |registry|
- items.each do |k,v|
- registry.register(k) { v }
- end
- end
- end
-
let(:env) do
isolated_environment.tap do |env|
env.vagrantfile("")
@@ -22,7 +14,7 @@ describe VagrantPlugins::CommandPush::Command do
end
let(:argv) { [] }
- let(:pushes) { create_registry }
+ let(:pushes) { {} }
subject { described_class.new(argv, env) }
@@ -50,7 +42,7 @@ describe VagrantPlugins::CommandPush::Command do
describe "#validate_pushes!" do
context "when there are no pushes defined" do
- let(:pushes) { create_registry }
+ let(:pushes) { {} }
context "when a strategy is given" do
it "raises an exception" do
@@ -69,7 +61,7 @@ describe VagrantPlugins::CommandPush::Command do
context "when there is one push defined" do
let(:noop) { double("noop") }
- let(:pushes) { create_registry(noop: noop) }
+ let(:pushes) { { noop: noop } }
context "when a strategy is given" do
context "when that strategy is not defined" do
@@ -98,7 +90,7 @@ describe VagrantPlugins::CommandPush::Command do
context "when there are multiple pushes defined" do
let(:noop) { double("noop") }
let(:ftp) { double("ftp") }
- let(:pushes) { create_registry(noop: noop, ftp: ftp) }
+ let(:pushes) { { noop: noop, ftp: ftp } }
context "when a strategy is given" do
context "when that strategy is not defined" do
From 190da2640492f4bfe70ca3e3908425f0dfbcdc4a Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 23 Oct 2014 16:02:51 -0400
Subject: [PATCH 027/203] Push does not have access to @machine
---
plugins/pushes/noop/push.rb | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/plugins/pushes/noop/push.rb b/plugins/pushes/noop/push.rb
index 490e32188..537ea1c7d 100644
--- a/plugins/pushes/noop/push.rb
+++ b/plugins/pushes/noop/push.rb
@@ -2,9 +2,7 @@ module VagrantPlugins
module NoopDeploy
class Push < Vagrant.plugin("2", :push)
def push
- @machine.communicate.tap do |comm|
- puts "pushed"
- end
+ puts "pushed"
end
end
end
From 988518a6ba0deea79ead95a30dbcb33d27a00c5b Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 23 Oct 2014 16:06:25 -0400
Subject: [PATCH 028/203] Make Environment#pushes its own method
---
lib/vagrant/environment.rb | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb
index f89c94773..106d0d9c5 100644
--- a/lib/vagrant/environment.rb
+++ b/lib/vagrant/environment.rb
@@ -545,21 +545,21 @@ module Vagrant
def push(name=nil)
@logger.info("Getting push: #{name}")
- if vagrantfile.pushes.nil? || vagrantfile.pushes.empty?
+ if pushes.nil? || pushes.empty?
raise Vagrant::Errors::PushesNotDefined
end
if name.nil?
- if vagrantfile.pushes.length != 1
+ if pushes.length != 1
raise Vagrant::Errors::PushStrategyNotProvided,
- pushes: vagrantfile.pushes
+ pushes: pushes
end
- name = vagrantfile.pushes.first
+ name = pushes.first
else
- if !vagrantfile.pushes.include?(name.to_sym)
+ if !pushes.include?(name.to_sym)
raise Vagrant::Errors::PushStrategyNotDefined,
name: name,
- pushes: vagrantfile.pushes
+ pushes: pushes
end
end
@@ -584,6 +584,13 @@ module Vagrant
end
end
+ # The list of pushes defined in this Vagrantfile.
+ #
+ # @return [Array]
+ def pushes
+ vagrantfile.pushes
+ end
+
# This returns a machine with the proper provider for this environment.
# The machine named by `name` must be in this environment.
#
From 3871154a74b8579eb36e765d338c69db5e003654 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 23 Oct 2014 16:27:21 -0400
Subject: [PATCH 029/203] Ignore options that come back from the plugin for now
---
lib/vagrant/environment.rb | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb
index 106d0d9c5..0d6a2a103 100644
--- a/lib/vagrant/environment.rb
+++ b/lib/vagrant/environment.rb
@@ -567,10 +567,7 @@ module Vagrant
push_config = vagrantfile.push(name)
push_config.each do |strategy, config_blocks|
- plugin, options = push_registry.get(strategy)
-
- # TODO: What do we do with options?
- # options
+ plugin, _ = push_registry.get(strategy)
if plugin.nil?
raise Vagrant::Errors::PushStrategyNotLoaded,
From 413565f96137a995407ab04113fa408b350235b3 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 24 Oct 2014 15:44:56 -0400
Subject: [PATCH 030/203] Simplify the API for Environment#push
The API has a precondition that `name` is not nil
---
lib/vagrant/environment.rb | 50 ++++++++++++++------------------------
1 file changed, 18 insertions(+), 32 deletions(-)
diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb
index 0d6a2a103..82cab0411 100644
--- a/lib/vagrant/environment.rb
+++ b/lib/vagrant/environment.rb
@@ -542,50 +542,36 @@ module Vagrant
# This executes the push with the given name, raising any exceptions that
# occur.
#
- def push(name=nil)
+ # Precondition: the push is not nil and exists.
+ def push(name)
@logger.info("Getting push: #{name}")
- if pushes.nil? || pushes.empty?
- raise Vagrant::Errors::PushesNotDefined
- end
-
- if name.nil?
- if pushes.length != 1
- raise Vagrant::Errors::PushStrategyNotProvided,
- pushes: pushes
- end
- name = pushes.first
- else
- if !pushes.include?(name.to_sym)
- raise Vagrant::Errors::PushStrategyNotDefined,
- name: name,
- pushes: pushes
- end
+ name = name.to_sym
+
+ pushes = self.vagrantfile.config.push.__compiled_pushes
+ if !pushes.key?(name)
+ raise Vagrant::Errors::PushStrategyNotDefined,
+ name: name,
+ pushes: pushes.keys
end
+ strategy, config = pushes[name]
push_registry = Vagrant.plugin("2").manager.pushes
-
- push_config = vagrantfile.push(name)
- push_config.each do |strategy, config_blocks|
- plugin, _ = push_registry.get(strategy)
-
- if plugin.nil?
- raise Vagrant::Errors::PushStrategyNotLoaded,
- name: strategy,
- pushes: push_registry.keys
- end
-
- # TODO: This should take a plugin configuration, not a list of config
- # blocks, or should it?
- plugin.new(self, config_blocks).push
+ klass, _ = push_registry.get(strategy)
+ if klass.nil?
+ raise Vagrant::Errors::PushStrategyNotLoaded,
+ name: strategy,
+ pushes: push_registry.keys
end
+
+ klass.new(self, config).push
end
# The list of pushes defined in this Vagrantfile.
#
# @return [Array]
def pushes
- vagrantfile.pushes
+ vagrantfile.config.push.__compiled_pushes.keys
end
# This returns a machine with the proper provider for this environment.
From e5b10aa86bfa7d413cacd2ff630ac137dff4c370 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 24 Oct 2014 15:45:33 -0400
Subject: [PATCH 031/203] Collect push_configs in the Plugin Manager
---
lib/vagrant/plugin/v2/manager.rb | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/lib/vagrant/plugin/v2/manager.rb b/lib/vagrant/plugin/v2/manager.rb
index d8f5296db..ce76d1fc1 100644
--- a/lib/vagrant/plugin/v2/manager.rb
+++ b/lib/vagrant/plugin/v2/manager.rb
@@ -183,6 +183,17 @@ module Vagrant
end
end
+ # This returns all the config classes for the various pushes.
+ #
+ # @return [Registry]
+ def push_configs
+ Registry.new.tap do |result|
+ @registered.each do |plugin|
+ result.merge!(plugin.components.configs[:push])
+ end
+ end
+ end
+
# This returns all synced folder implementations.
#
# @return [Registry]
From 8e2f18761f7d09eaa8be69e3d1ee4cf1f3f99578 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 24 Oct 2014 15:45:42 -0400
Subject: [PATCH 032/203] Remove unused methods from vagrantfile.rb
---
lib/vagrant/vagrantfile.rb | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/lib/vagrant/vagrantfile.rb b/lib/vagrant/vagrantfile.rb
index 7467ffbbc..011d16351 100644
--- a/lib/vagrant/vagrantfile.rb
+++ b/lib/vagrant/vagrantfile.rb
@@ -247,20 +247,6 @@ module Vagrant
nil
end
- # Returns the list of defined pushes in this Vagrantfile.
- #
- # @return [Array]
- def pushes
- @config.push.defined_pushes
- end
-
- # Get the push by the given name.
- #
- # @return [idk]
- def push(name)
- @config.push.get_push(name)
- end
-
protected
def find_vagrantfile(search_path)
From 411c7d6f7514c8657ed9bcd088675c1e7bb26dba Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 24 Oct 2014 15:46:09 -0400
Subject: [PATCH 033/203] Define finalize! and __compiled_pushes for Push
config
---
plugins/kernel_v2/config/push.rb | 79 +++++++++++++++++++++-----------
1 file changed, 53 insertions(+), 26 deletions(-)
diff --git a/plugins/kernel_v2/config/push.rb b/plugins/kernel_v2/config/push.rb
index c5c3a10b0..e8ce5a3ee 100644
--- a/plugins/kernel_v2/config/push.rb
+++ b/plugins/kernel_v2/config/push.rb
@@ -8,12 +8,59 @@ module VagrantPlugins
attr_accessor :name
def initialize
+ @logger = Log4r::Logger.new("vagrant::config::push")
+
# Internal state
- @__defined_pushes = {}
- @__finalized = false
+ @__defined_pushes = {}
+ @__compiled_pushes = {}
+ @__finalized = false
end
def finalize!
+ @logger.debug("finalizing")
+
+ # Compile all the provider configurations
+ @__defined_pushes.each do |name, tuples|
+ # Find the configuration class for this push
+ config_class = Vagrant.plugin("2").manager.push_configs[name]
+ config_class ||= Vagrant::Config::V2::DummyConfig
+
+ # Load it up
+ config = config_class.new
+
+ # Capture the strategy so we can use it later. This will be used in
+ # the block iteration for merging/overwriting
+ strategy = (tuples[0] && tuples[0][0]) || name
+
+ begin
+ tuples.each do |s, b|
+ # Update the strategy if it has changed, reseting the current
+ # config object.
+ if s != strategy
+ @logger.warn("duplicate strategy defined, overwriting config")
+ strategy = s
+ config = config_class.new
+ end
+
+ # If we don't have any blocks, then ignore it
+ next if b.nil?
+
+ new_config = config_class.new
+ b.call(new_config, Vagrant::Config::V2::DummyConfig.new)
+ config = config.merge(new_config)
+ end
+ rescue Exception => e
+ raise Vagrant::Errors::VagrantfileLoadError,
+ path: "",
+ message: e.message
+ end
+
+ config.finalize!
+
+ # Store it for retrieval later
+ @__compiled_pushes[name] = [strategy, config]
+ end
+
@__finalized = true
end
@@ -38,8 +85,6 @@ module VagrantPlugins
# @param [Hash] options The list of options
#
def define(name, **options, &block)
- validate_options!(options)
-
name = name.to_sym
strategy = options[:strategy] || name
@@ -69,30 +114,12 @@ module VagrantPlugins
end
end
- # This returns the list of pushes defined in the Vagrantfile.
+ # This returns the list of compiled pushes as a hash by name.
#
- # @return [Array]
- def defined_pushes
+ # @return [Hash>]
+ def __compiled_pushes
raise "Must finalize first!" if !@__finalized
- @__defined_pushes.keys
- end
-
- # This returns the compiled push-specific configuration for the given
- # provider.
- #
- # @param [#to_sym] name Name of the push
- def get_push(name)
- raise "Must finalize first!" if !@__finalized
- @__defined_pushes[name.to_sym]
- end
-
- private
-
- def validate_options!(options)
- extra_keys = VALID_OPTIONS - options.keys
- if !extra_keys.empty?
- raise "Invalid option(s): #{extra_keys.join(", ")}"
- end
+ @__compiled_pushes.dup
end
end
end
From 88aa1063278e2c12cc9662f14e75e3c3e3679b06 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 24 Oct 2014 15:46:16 -0400
Subject: [PATCH 034/203] Fix up i18n missing translation
---
templates/locales/en.yml | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index fa3c76414..37ed84f07 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -957,19 +957,18 @@ en:
The push strategy '%{name}' is not defined in the Vagrantfile. Defined
strategy names are:
- %{pushes}
-
- push_strategy_not_defined: |-
+ %{pushes}
+ push_strategy_not_loaded: |-
There are no push strategies named '%{name}'. Please make sure you
spelled it correctly. If you are using an external push strategy, you
may need to install a plugin. Loaded push strategies are:
- %{pushes}
+ %{pushes}
push_strategy_not_provided: |-
The Vagrantfile defines more than one 'push' strategy. Please specify a
strategy. Defined strategy names are:
- %{pushes}
+ %{pushes}
package_include_symlink: |-
A file or directory you're attempting to include with your packaged
box has symlinks in it. Vagrant cannot include symlinks in the
From 7f6a4fa3bdb54930c483badcd3d865aa33cd9220 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 24 Oct 2014 15:46:34 -0400
Subject: [PATCH 035/203] Add tests for plugin manager push_configs
---
test/unit/vagrant/plugin/v2/manager_test.rb | 36 +++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/test/unit/vagrant/plugin/v2/manager_test.rb b/test/unit/vagrant/plugin/v2/manager_test.rb
index 45ebd5a0c..3ddbf00e9 100644
--- a/test/unit/vagrant/plugin/v2/manager_test.rb
+++ b/test/unit/vagrant/plugin/v2/manager_test.rb
@@ -189,6 +189,42 @@ describe Vagrant::Plugin::V2::Manager do
expect(instance.provider_configs[:bar]).to eq("bar")
end
+ it "should enumerate registered push classes" do
+ pA = plugin do |p|
+ p.push("foo") { "bar" }
+ end
+
+ pB = plugin do |p|
+ p.push("bar", foo: "bar") { "baz" }
+ end
+
+ instance.register(pA)
+ instance.register(pB)
+
+ expect(instance.pushes.to_hash.length).to eq(2)
+ expect(instance.pushes[:foo]).to eq(["bar", nil])
+ expect(instance.pushes[:bar]).to eq(["baz", { foo: "bar" }])
+ end
+
+ it "provides the collection of registered push configs" do
+ pA = plugin do |p|
+ p.config("foo", :push) { "foo" }
+ end
+
+ pB = plugin do |p|
+ p.config("bar", :push) { "bar" }
+ p.config("baz") { "baz" }
+ end
+
+ instance.register(pA)
+ instance.register(pB)
+
+ expect(instance.push_configs.to_hash.length).to eq(2)
+ expect(instance.push_configs[:foo]).to eq("foo")
+ expect(instance.push_configs[:bar]).to eq("bar")
+ end
+
+
it "should enumerate all registered synced folder implementations" do
pA = plugin do |p|
p.synced_folder("foo") { "bar" }
From f3c35855f06e2cb8ebe05a5dc23f0fc54627f69f Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 24 Oct 2014 15:46:44 -0400
Subject: [PATCH 036/203] Add a newline because #ocd
---
test/unit/vagrant/plugin/v2/plugin_test.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/unit/vagrant/plugin/v2/plugin_test.rb b/test/unit/vagrant/plugin/v2/plugin_test.rb
index 442462805..76ad40993 100644
--- a/test/unit/vagrant/plugin/v2/plugin_test.rb
+++ b/test/unit/vagrant/plugin/v2/plugin_test.rb
@@ -357,6 +357,7 @@ describe Vagrant::Plugin::V2::Plugin do
}.to raise_error(StandardError)
end
end
+
describe "synced folders" do
it "should register implementations" do
plugin = Class.new(described_class) do
From 111a43552ec082926b0c0b23fc578c57d59c254a Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 24 Oct 2014 15:46:57 -0400
Subject: [PATCH 037/203] Add tests for Environment#pushes and #Enviroment#push
---
test/unit/vagrant/environment_test.rb | 70 +++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/test/unit/vagrant/environment_test.rb b/test/unit/vagrant/environment_test.rb
index 2bb52e939..02effd7db 100644
--- a/test/unit/vagrant/environment_test.rb
+++ b/test/unit/vagrant/environment_test.rb
@@ -968,6 +968,76 @@ VF
end
end
+ describe "#pushes" do
+ it "returns the pushes from the Vagrantfile config" do
+ environment = isolated_environment do |env|
+ env.vagrantfile(<<-VF.gsub(/^ {10}/, ''))
+ Vagrant.configure("2") do |config|
+ config.push.define "noop"
+ end
+ VF
+ end
+
+ env = environment.create_vagrant_env
+ expect(env.pushes).to eq([:noop])
+ end
+ end
+
+ describe "#push" do
+ let(:push_class) do
+ Class.new(Vagrant.plugin("2", :push)) do
+ def self.pushed?
+ !!class_variable_get(:@@pushed)
+ end
+
+ def push
+ !!self.class.class_variable_set(:@@pushed, true)
+ end
+ end
+ end
+
+ it "raises an exception when the push does not exist" do
+ expect { instance.push("lolwatbacon") }
+ .to raise_error(Vagrant::Errors::PushStrategyNotDefined)
+ end
+
+ it "raises an exception if the strategy does not exist" do
+ environment = isolated_environment do |env|
+ env.vagrantfile(<<-VF.gsub(/^ {10}/, ''))
+ Vagrant.configure("2") do |config|
+ config.push.define "lolwatbacon"
+ end
+ VF
+ end
+
+ env = environment.create_vagrant_env
+ expect { env.push("lolwatbacon") }
+ .to raise_error(Vagrant::Errors::PushStrategyNotLoaded)
+ end
+
+ it "executes the push action" do
+ register_plugin("2") do |plugin|
+ plugin.name "foo"
+
+ plugin.push(:foo) do
+ push_class
+ end
+ end
+
+ environment = isolated_environment do |env|
+ env.vagrantfile(<<-VF.gsub(/^ {10}/, ''))
+ Vagrant.configure("2") do |config|
+ config.push.define "foo"
+ end
+ VF
+ end
+
+ env = environment.create_vagrant_env
+ env.push("foo")
+ expect(push_class.pushed?).to be_true
+ end
+ end
+
describe "#hook" do
it "should call the action runner with the proper hook" do
hook_name = :foo
From 41ac448ba8540110db90838a902d8c8b6f69675a Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 24 Oct 2014 15:47:07 -0400
Subject: [PATCH 038/203] Add tests for Push config merging and finalizing
---
.../plugins/kernel_v2/config/push_test.rb | 300 ++++++++++++++++++
1 file changed, 300 insertions(+)
create mode 100644 test/unit/plugins/kernel_v2/config/push_test.rb
diff --git a/test/unit/plugins/kernel_v2/config/push_test.rb b/test/unit/plugins/kernel_v2/config/push_test.rb
new file mode 100644
index 000000000..28430d171
--- /dev/null
+++ b/test/unit/plugins/kernel_v2/config/push_test.rb
@@ -0,0 +1,300 @@
+require File.expand_path("../../../../base", __FILE__)
+
+require Vagrant.source_root.join("plugins/kernel_v2/config/push")
+
+describe VagrantPlugins::Kernel_V2::PushConfig do
+ include_context "unit"
+
+ subject { described_class.new }
+
+ describe "#define" do
+ let(:pushes) { subject.instance_variable_get(:@__defined_pushes) }
+
+ it "pushes the strategy and block onto the defined pushes array" do
+ subject.define("foo") { "bar" }
+ subject.define("foo") { "zip" }
+ subject.define("foo") { "zap" }
+
+ expect(pushes.size).to eq(1)
+ expect(pushes[:foo].size).to eq(3)
+ expect(pushes[:foo][0]).to be_a(Array)
+ expect(pushes[:foo][0][0]).to eq(:foo)
+ expect(pushes[:foo][0][1]).to be_a(Proc)
+ end
+
+ context "when no strategy is given" do
+ it "defaults to the name" do
+ subject.define("foo") { "bar" }
+
+ expect(pushes.size).to eq(1)
+ expect(pushes[:foo].size).to eq(1)
+ expect(pushes[:foo][0]).to be_a(Array)
+ expect(pushes[:foo][0][0]).to eq(:foo)
+ expect(pushes[:foo][0][1]).to be_a(Proc)
+ end
+ end
+
+ context "when a strategy is given" do
+ it "uses the strategy" do
+ subject.define("foo", strategy: "bacon") { "bar" }
+
+ expect(pushes.size).to eq(1)
+ expect(pushes[:foo].size).to eq(1)
+ expect(pushes[:foo][0]).to be_a(Array)
+ expect(pushes[:foo][0][0]).to eq(:bacon)
+ expect(pushes[:foo][0][1]).to be_a(Proc)
+ end
+ end
+ end
+
+ describe "#merge" do
+ it "appends defined pushes" do
+ a = described_class.new.tap do |i|
+ i.define("foo") { "bar" }
+ i.define("bar") { "bar" }
+ end
+ b = described_class.new.tap do |i|
+ i.define("foo") { "zip" }
+ end
+
+ result = a.merge(b)
+ pushes = result.instance_variable_get(:@__defined_pushes)
+
+ expect(pushes[:foo]).to be_a(Array)
+ expect(pushes[:foo].size).to eq(2)
+
+ expect(pushes[:bar]).to be_a(Array)
+ expect(pushes[:bar].size).to eq(1)
+ end
+ end
+
+ describe "#__compiled_pushes" do
+ it "raises an exception if not finalized" do
+ subject.instance_variable_set(:@__finalized, false)
+ expect { subject.__compiled_pushes }.to raise_error
+ end
+
+ it "returns a copy of the compiled pushes" do
+ pushes = { foo: "bar" }
+ subject.instance_variable_set(:@__finalized, true)
+ subject.instance_variable_set(:@__compiled_pushes, pushes)
+
+ expect(subject.__compiled_pushes).to_not be(pushes)
+ expect(subject.__compiled_pushes).to eq(pushes)
+ end
+ end
+
+ describe "#finalize!" do
+ let(:pushes) { a.merge(b).tap { |r| r.finalize! }.__compiled_pushes }
+ let(:key) { pushes[:foo][0] }
+ let(:config) { pushes[:foo][1] }
+ let(:unset) { Vagrant.plugin("2", :config).const_get(:UNSET_VALUE) }
+
+ before do
+ register_plugin("2") do |plugin|
+ plugin.name "foo"
+
+ plugin.push(:foo) do
+ Class.new(Vagrant.plugin("2", :push))
+ end
+
+ plugin.config(:foo, :push) do
+ Class.new(Vagrant.plugin("2", :config)) do
+ attr_accessor :bar
+ attr_accessor :zip
+
+ def initialize
+ @bar = self.class.const_get(:UNSET_VALUE)
+ @zip = self.class.const_get(:UNSET_VALUE)
+ end
+ end
+ end
+ end
+ end
+
+ context "with the same name but different strategy" do
+ context "with no block" do
+ let(:a) do
+ described_class.new.tap do |i|
+ i.define("foo", strategy: "bar")
+ end
+ end
+
+ let(:b) do
+ described_class.new.tap do |i|
+ i.define("foo", strategy: "zip")
+ end
+ end
+
+ it "chooses the last config" do
+ expect(key).to eq(:zip)
+ expect(config.bar).to be(unset)
+ expect(config.zip).to be(unset)
+ end
+ end
+
+ context "with a block" do
+ let(:a) do
+ described_class.new.tap do |i|
+ i.define("foo", strategy: "bar") do |p|
+ p.bar = "a"
+ end
+ end
+ end
+
+ let(:b) do
+ described_class.new.tap do |i|
+ i.define("foo", strategy: "zip") do |p|
+ p.zip = "b"
+ end
+ end
+ end
+
+ it "chooses the last config" do
+ expect(key).to eq(:zip)
+ expect(config.bar).to eq(unset)
+ expect(config.zip).to eq("b")
+ end
+ end
+
+ context "with a block, then no block" do
+ let(:a) do
+ described_class.new.tap do |i|
+ i.define("foo", strategy: "bar") do |p|
+ p.bar, p.zip = "a", "a"
+ end
+ end
+ end
+
+ let(:b) do
+ described_class.new.tap do |i|
+ i.define("foo", strategy: "zip")
+ end
+ end
+
+ it "chooses the last config" do
+ expect(key).to eq(:zip)
+ expect(config.bar).to be(unset)
+ expect(config.zip).to be(unset)
+ end
+ end
+
+ context "with no block, then a block" do
+ let(:a) do
+ described_class.new.tap do |i|
+ i.define("foo", strategy: "bar")
+ end
+ end
+
+ let(:b) do
+ described_class.new.tap do |i|
+ i.define("foo", strategy: "zip") do |p|
+ p.bar, p.zip = "b", "b"
+ end
+ end
+ end
+
+ it "chooses the last config" do
+ expect(key).to eq(:zip)
+ expect(config.bar).to eq("b")
+ expect(config.zip).to eq("b")
+ end
+ end
+ end
+
+ context "with the same name twice" do
+ context "with no block" do
+ let(:a) do
+ described_class.new.tap do |i|
+ i.define("foo")
+ end
+ end
+
+ let(:b) do
+ described_class.new.tap do |i|
+ i.define("foo")
+ end
+ end
+
+ it "merges the configs" do
+ expect(key).to eq(:foo)
+ expect(config.bar).to be(unset)
+ expect(config.zip).to be(unset)
+ end
+ end
+
+ context "with a block" do
+ let(:a) do
+ described_class.new.tap do |i|
+ i.define("foo") do |p|
+ p.bar = "a"
+ end
+ end
+ end
+
+ let(:b) do
+ described_class.new.tap do |i|
+ i.define("foo") do |p|
+ p.zip = "b"
+ end
+ end
+ end
+
+ it "merges the configs" do
+ expect(key).to eq(:foo)
+ expect(config.bar).to eq("a")
+ expect(config.zip).to eq("b")
+ end
+ end
+
+ context "with a block, then no block" do
+ let(:a) do
+ described_class.new.tap do |i|
+ i.define("foo") do |p|
+ p.bar = "a"
+ end
+ end
+ end
+
+ let(:b) do
+ described_class.new.tap do |i|
+ i.define("foo")
+ end
+ end
+
+ it "merges the configs" do
+ expect(key).to eq(:foo)
+ expect(config.bar).to eq("a")
+ expect(config.zip).to be(unset)
+ end
+ end
+
+ context "with no block, then a block" do
+ let(:a) do
+ described_class.new.tap do |i|
+ i.define("foo", strategy: "bar")
+ end
+ end
+
+ let(:b) do
+ described_class.new.tap do |i|
+ i.define("foo", strategy: "zip") do |p|
+ p.zip = "b"
+ end
+ end
+ end
+
+ it "merges the configs" do
+ expect(key).to eq(:zip)
+ expect(config.bar).to eq(unset)
+ expect(config.zip).to eq("b")
+ end
+ end
+ end
+
+ it "sets @__finalized to true" do
+ subject.finalize!
+ expect(subject.instance_variable_get(:@__finalized)).to be(true)
+ end
+ end
+end
From 35b7e28011ff5594d769b36d66a91b2acaa564fc Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 24 Oct 2014 19:49:10 -0400
Subject: [PATCH 039/203] Do not use UNSET_VALUE in plugin (it uses components)
---
lib/vagrant/plugin/v2/plugin.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/vagrant/plugin/v2/plugin.rb b/lib/vagrant/plugin/v2/plugin.rb
index bcae23eaa..a39b3cf10 100644
--- a/lib/vagrant/plugin/v2/plugin.rb
+++ b/lib/vagrant/plugin/v2/plugin.rb
@@ -225,7 +225,7 @@ module Vagrant
#
# @param [String] name Name of the push.
# @param [Hash] options List of options for the push.
- def self.push(name=UNSET_VALUE, options=nil, &block)
+ def self.push(name, options=nil, &block)
components.pushes.register(name.to_sym) do
[block.call, options]
end
From 1121e96cf7db961bf19294263154527b5eb9d23e Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 24 Oct 2014 19:49:58 -0400
Subject: [PATCH 040/203] Remove TODO comment about duplicate code
---
plugins/commands/push/command.rb | 2 --
1 file changed, 2 deletions(-)
diff --git a/plugins/commands/push/command.rb b/plugins/commands/push/command.rb
index ec7324b55..dc02f7ba7 100644
--- a/plugins/commands/push/command.rb
+++ b/plugins/commands/push/command.rb
@@ -20,8 +20,6 @@ module VagrantPlugins
name = argv[0]
pushes = @env.pushes
- # TODO: this logic is 100% duplicated in Enviroment#push - should we
- # just not validate here?
validate_pushes!(pushes, name)
@logger.debug("'push' environment with strategy: `#{name}'")
From 9af7675bd3a1828f606c31b5717885c6a8e1c752 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 24 Oct 2014 19:50:52 -0400
Subject: [PATCH 041/203] Use a more readable version for setter
---
plugins/kernel_v2/config/push.rb | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/plugins/kernel_v2/config/push.rb b/plugins/kernel_v2/config/push.rb
index e8ce5a3ee..e0137b29d 100644
--- a/plugins/kernel_v2/config/push.rb
+++ b/plugins/kernel_v2/config/push.rb
@@ -30,7 +30,8 @@ module VagrantPlugins
# Capture the strategy so we can use it later. This will be used in
# the block iteration for merging/overwriting
- strategy = (tuples[0] && tuples[0][0]) || name
+ strategy = name
+ strategy = tuples[0][0] if tuples[0]
begin
tuples.each do |s, b|
From e7b0661a93a9718604cd0da0e8e07db01763c65f Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Tue, 28 Oct 2014 20:54:16 -0700
Subject: [PATCH 042/203] pushes/harmony: boilerplate, config
---
plugins/pushes/harmony/config.rb | 73 ++++++++++++++++
plugins/pushes/harmony/plugin.rb | 22 +++++
plugins/pushes/harmony/push.rb | 9 ++
.../plugins/pushes/harmony/config_test.rb | 84 +++++++++++++++++++
4 files changed, 188 insertions(+)
create mode 100644 plugins/pushes/harmony/config.rb
create mode 100644 plugins/pushes/harmony/plugin.rb
create mode 100644 plugins/pushes/harmony/push.rb
create mode 100644 test/unit/plugins/pushes/harmony/config_test.rb
diff --git a/plugins/pushes/harmony/config.rb b/plugins/pushes/harmony/config.rb
new file mode 100644
index 000000000..5053c328e
--- /dev/null
+++ b/plugins/pushes/harmony/config.rb
@@ -0,0 +1,73 @@
+module VagrantPlugins
+ module HarmonyPush
+ class Config < Vagrant.plugin("2", :config)
+ # The name of the application to push to. This will be created (with
+ # user confirmation) if it doesn't already exist.
+ #
+ # @return [String]
+ attr_accessor :app
+
+ # The base directory with file contents to upload. By default this
+ # is the same directory as the Vagrantfile, but you can specify this
+ # if you have a `src` folder or `bin` folder or some other folder
+ # you want to upload.
+ #
+ # @return [String]
+ attr_accessor :dir
+
+ # Lists of files to include/exclude in what is uploaded. Exclude is
+ # always the last run filter, so if a file is matched in both include
+ # and exclude, it will be excluded.
+ #
+ # The value of the array elements should be a simple file glob relative
+ # to the directory being packaged.
+ #
+ # @return [Array]
+ attr_accessor :include
+ attr_accessor :exclude
+
+ # If set to true, Vagrant will automatically use VCS data to determine
+ # the files to upload. As a caveat: uncommitted changes will not be
+ # deployed.
+ #
+ # @return [Boolean]
+ attr_accessor :vcs
+
+ def initialize
+ @app = UNSET_VALUE
+ @dir = UNSET_VALUE
+ @vcs = UNSET_VALUE
+ @include = []
+ @exclude = []
+ end
+
+ def merge(other)
+ super.tap do |result|
+ inc = self.include.dup
+ inc.concat(other.include)
+ result.include = inc
+
+ exc = self.exclude.dup
+ exc.concat(other.exclude)
+ result.exclude = exc
+ end
+ end
+
+ def finalize!
+ @app = nil if @app == UNSET_VALUE
+ @dir = "." if @dir == UNSET_VALUE
+ @vcs = true if @vcs == UNSET_VALUE
+ end
+
+ def validate(machine)
+ errors = _detected_errors
+
+ if @app == nil || @app == ""
+ errors << I18n.t("push_harmony.errors.config.app_required")
+ end
+
+ { "Harmony push" => errors }
+ end
+ end
+ end
+end
diff --git a/plugins/pushes/harmony/plugin.rb b/plugins/pushes/harmony/plugin.rb
new file mode 100644
index 000000000..a0c013f82
--- /dev/null
+++ b/plugins/pushes/harmony/plugin.rb
@@ -0,0 +1,22 @@
+require "vagrant"
+
+module VagrantPlugins
+ module HarmonyPush
+ class Plugin < Vagrant.plugin("2")
+ name "harmony"
+ description <<-DESC
+ Deploy using HashiCorp's Harmony service.
+ DESC
+
+ config(:harmony, :push) do
+ require File.expand_path("../config", __FILE__)
+ Config
+ end
+
+ push(:harmony) do
+ require File.expand_path("../push", __FILE__)
+ Push
+ end
+ end
+ end
+end
diff --git a/plugins/pushes/harmony/push.rb b/plugins/pushes/harmony/push.rb
new file mode 100644
index 000000000..20f1c355e
--- /dev/null
+++ b/plugins/pushes/harmony/push.rb
@@ -0,0 +1,9 @@
+module VagrantPlugins
+ module HarmonyPush
+ class Push < Vagrant.plugin("2", :push)
+ def push
+ puts "pushed"
+ end
+ end
+ end
+end
diff --git a/test/unit/plugins/pushes/harmony/config_test.rb b/test/unit/plugins/pushes/harmony/config_test.rb
new file mode 100644
index 000000000..de5ce1c33
--- /dev/null
+++ b/test/unit/plugins/pushes/harmony/config_test.rb
@@ -0,0 +1,84 @@
+require_relative "../../../base"
+
+require Vagrant.source_root.join("plugins/pushes/harmony/config")
+
+describe VagrantPlugins::HarmonyPush::Config do
+ include_context "unit"
+
+ let(:machine) { double("machine") }
+
+ # For testing merging
+ let(:one) { described_class.new }
+ let(:two) { described_class.new }
+
+ def assert_invalid
+ errors = subject.validate(machine)
+ if !errors.values.any? { |v| !v.empty? }
+ raise "No errors: #{errors.inspect}"
+ end
+ end
+
+ def assert_valid
+ errors = subject.validate(machine)
+ if !errors.values.all? { |v| v.empty? }
+ raise "Errors: #{errors.inspect}"
+ end
+ end
+
+ def valid_defaults
+ end
+
+ describe "defaults" do
+ before { subject.finalize! }
+
+ its(:app) { should be_nil }
+ its(:dir) { should eq(".") }
+ its(:exclude) { should be_empty }
+ its(:include) { should be_empty }
+ its(:vcs) { should be_true }
+ end
+
+ describe "app" do
+ before do
+ valid_defaults
+ end
+
+ it "is invalid if not set" do
+ subject.app = ""
+ subject.finalize!
+ assert_invalid
+ end
+
+ it "is valid if set" do
+ subject.app = "foo/bar"
+ subject.finalize!
+ assert_valid
+ end
+ end
+
+ describe "exclude" do
+ context "merge" do
+ subject { one.merge(two) }
+
+ it "appends" do
+ one.exclude = ["foo"]
+ two.exclude = ["bar"]
+
+ expect(subject.exclude).to eq(["foo", "bar"])
+ end
+ end
+ end
+
+ describe "include" do
+ context "merge" do
+ subject { one.merge(two) }
+
+ it "appends" do
+ one.include = ["foo"]
+ two.include = ["bar"]
+
+ expect(subject.include).to eq(["foo", "bar"])
+ end
+ end
+ end
+end
From 168715ad7d2bd8a703b1ddb99c0fa06c706930f3 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 29 Oct 2014 00:05:31 -0700
Subject: [PATCH 043/203] push/harmony: ability to set uploader path
---
plugins/pushes/harmony/config.rb | 10 ++++++++++
test/unit/plugins/pushes/harmony/config_test.rb | 1 +
2 files changed, 11 insertions(+)
diff --git a/plugins/pushes/harmony/config.rb b/plugins/pushes/harmony/config.rb
index 5053c328e..d9890079e 100644
--- a/plugins/pushes/harmony/config.rb
+++ b/plugins/pushes/harmony/config.rb
@@ -33,12 +33,21 @@ module VagrantPlugins
# @return [Boolean]
attr_accessor :vcs
+ # The path to the uploader binary to shell out to. This usually
+ # is only set for debugging/development. If not set, the uploader
+ # will be looked for within the Vagrant installer dir followed by
+ # the PATH.
+ #
+ # @return [String]
+ attr_accessor :uploader_path
+
def initialize
@app = UNSET_VALUE
@dir = UNSET_VALUE
@vcs = UNSET_VALUE
@include = []
@exclude = []
+ @uploader_path = UNSET_VALUE
end
def merge(other)
@@ -56,6 +65,7 @@ module VagrantPlugins
def finalize!
@app = nil if @app == UNSET_VALUE
@dir = "." if @dir == UNSET_VALUE
+ @uploader_path = nil if @uploader_path == UNSET_VALUE
@vcs = true if @vcs == UNSET_VALUE
end
diff --git a/test/unit/plugins/pushes/harmony/config_test.rb b/test/unit/plugins/pushes/harmony/config_test.rb
index de5ce1c33..0806156e3 100644
--- a/test/unit/plugins/pushes/harmony/config_test.rb
+++ b/test/unit/plugins/pushes/harmony/config_test.rb
@@ -35,6 +35,7 @@ describe VagrantPlugins::HarmonyPush::Config do
its(:dir) { should eq(".") }
its(:exclude) { should be_empty }
its(:include) { should be_empty }
+ its(:uploader_path) { should be_nil }
its(:vcs) { should be_true }
end
From efffc5f2f7a1b9374ff980c6bb30b0a47d403d9a Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 29 Oct 2014 09:39:26 -0700
Subject: [PATCH 044/203] push/harmony: basic push implementation
---
plugins/pushes/harmony/errors.rb | 13 +++
plugins/pushes/harmony/plugin.rb | 2 +
plugins/pushes/harmony/push.rb | 46 +++++++-
test/unit/plugins/pushes/harmony/push_test.rb | 103 ++++++++++++++++++
4 files changed, 163 insertions(+), 1 deletion(-)
create mode 100644 plugins/pushes/harmony/errors.rb
create mode 100644 test/unit/plugins/pushes/harmony/push_test.rb
diff --git a/plugins/pushes/harmony/errors.rb b/plugins/pushes/harmony/errors.rb
new file mode 100644
index 000000000..9eb590ff3
--- /dev/null
+++ b/plugins/pushes/harmony/errors.rb
@@ -0,0 +1,13 @@
+module VagrantPlugins
+ module HarmonyPush
+ module Errors
+ class Error < Vagrant::Errors::VagrantError
+ error_namespace("harmony_push.errors")
+ end
+
+ class UploaderNotFound < Error
+ error_key(:uploader_error)
+ end
+ end
+ end
+end
diff --git a/plugins/pushes/harmony/plugin.rb b/plugins/pushes/harmony/plugin.rb
index a0c013f82..bcf662c01 100644
--- a/plugins/pushes/harmony/plugin.rb
+++ b/plugins/pushes/harmony/plugin.rb
@@ -2,6 +2,8 @@ require "vagrant"
module VagrantPlugins
module HarmonyPush
+ autoload :Errors, File.expand_path("../errors", __FILE__)
+
class Plugin < Vagrant.plugin("2")
name "harmony"
description <<-DESC
diff --git a/plugins/pushes/harmony/push.rb b/plugins/pushes/harmony/push.rb
index 20f1c355e..5a3907249 100644
--- a/plugins/pushes/harmony/push.rb
+++ b/plugins/pushes/harmony/push.rb
@@ -1,8 +1,52 @@
+require "vagrant/util/safe_exec"
+require "vagrant/util/subprocess"
+require "vagrant/util/which"
+
module VagrantPlugins
module HarmonyPush
class Push < Vagrant.plugin("2", :push)
+ UPLOADER_BIN = "harmony-upload"
+
def push
- puts "pushed"
+ uploader = self.uploader_path
+
+ # If we didn't find the uploader binary it is a critical error
+ raise Errors::UploaderNotFound if !uploader
+
+ # We found it. Build up the command and the args.
+ execute(uploader)
+ return 0
+ end
+
+ # Executes the uploader with the proper flags based on the configuration.
+ # This function shouldn't return since it will exec, but might return
+ # if we're on a system that doesn't support exec, so handle that properly.
+ def execute(uploader)
+ cmd = []
+ cmd << "-vcs" if @config.vcs
+ cmd += @config.include.map { |v| ["-include", v] } if !@config.include.empty?
+ cmd += @config.exclude.map { |v| ["-exclude", v] } if !@config.exclude.empty?
+ cmd << @config.app
+ cmd << @config.dir
+ Vagrant::Util::SafeExec.exec(uploader, *cmd.flatten)
+ end
+
+ # This returns the path to the uploader binary, or nil if it can't
+ # be found.
+ #
+ # @return [String]
+ def uploader_path
+ # Determine the uploader path
+ uploader = @config.uploader_path
+ if uploader
+ return uploader
+ end
+
+ if Vagrant.in_installer?
+ # TODO: look up uploader in embedded dir
+ else
+ return Vagrant::Util::Which.which(UPLOADER_BIN)
+ end
end
end
end
diff --git a/test/unit/plugins/pushes/harmony/push_test.rb b/test/unit/plugins/pushes/harmony/push_test.rb
new file mode 100644
index 000000000..9b386370c
--- /dev/null
+++ b/test/unit/plugins/pushes/harmony/push_test.rb
@@ -0,0 +1,103 @@
+require_relative "../../../base"
+
+require Vagrant.source_root.join("plugins/pushes/harmony/config")
+require Vagrant.source_root.join("plugins/pushes/harmony/push")
+
+describe VagrantPlugins::HarmonyPush::Push do
+ include_context "unit"
+
+ let(:config) do
+ VagrantPlugins::HarmonyPush::Config.new.tap do |c|
+ c.finalize!
+ end
+ end
+
+ let(:machine) { double("machine") }
+
+ subject { described_class.new(machine, config) }
+
+ before do
+ # Stub this right away to avoid real execs
+ allow(Vagrant::Util::SafeExec).to receive(:exec)
+ end
+
+ describe "#push" do
+ it "pushes with the uploader" do
+ allow(subject).to receive(:uploader_path).and_return("foo")
+
+ expect(subject).to receive(:execute).with("foo")
+
+ subject.push
+ end
+
+ it "raises an exception if the uploader couldn't be found" do
+ expect(subject).to receive(:uploader_path).and_return(nil)
+
+ expect { subject.push }.to raise_error(
+ VagrantPlugins::HarmonyPush::Errors::UploaderNotFound)
+ end
+ end
+
+ describe "#execute" do
+ let(:app) { "foo/bar" }
+
+ before do
+ config.app = app
+ end
+
+ it "sends the basic flags" do
+ expect(Vagrant::Util::SafeExec).to receive(:exec).
+ with("foo", "-vcs", app, ".")
+
+ subject.execute("foo")
+ end
+
+ it "doesn't send VCS if disabled" do
+ expect(Vagrant::Util::SafeExec).to receive(:exec).
+ with("foo", app, ".")
+
+ config.vcs = false
+ subject.execute("foo")
+ end
+
+ it "sends includes" do
+ expect(Vagrant::Util::SafeExec).to receive(:exec).
+ with("foo", "-vcs", "-include", "foo", "-include", "bar", app, ".")
+
+ config.include = ["foo", "bar"]
+ subject.execute("foo")
+ end
+
+ it "sends excludes" do
+ expect(Vagrant::Util::SafeExec).to receive(:exec).
+ with("foo", "-vcs", "-exclude", "foo", "-exclude", "bar", app, ".")
+
+ config.exclude = ["foo", "bar"]
+ subject.execute("foo")
+ end
+ end
+
+ describe "#uploader_path" do
+ it "should return the configured path if set" do
+ config.uploader_path = "foo"
+ expect(subject.uploader_path).to eq("foo")
+ end
+
+ it "should look up the uploader via PATH if not set" do
+ allow(Vagrant).to receive(:in_installer?).and_return(false)
+
+ expect(Vagrant::Util::Which).to receive(:which).
+ with(described_class.const_get(:UPLOADER_BIN)).
+ and_return("bar")
+
+ expect(subject.uploader_path).to eq("bar")
+ end
+
+ it "should return nil if its not found anywhere" do
+ allow(Vagrant).to receive(:in_installer?).and_return(false)
+ allow(Vagrant::Util::Which).to receive(:which).and_return(nil)
+
+ expect(subject.uploader_path).to be_nil
+ end
+ end
+end
From f3f4f4aeb62c6893d3932b0c68f1e4cabe3461a5 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 29 Oct 2014 09:41:47 -0700
Subject: [PATCH 045/203] pushes/harmony: stub I18n
---
plugins/pushes/harmony/plugin.rb | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/plugins/pushes/harmony/plugin.rb b/plugins/pushes/harmony/plugin.rb
index bcf662c01..51630cfbf 100644
--- a/plugins/pushes/harmony/plugin.rb
+++ b/plugins/pushes/harmony/plugin.rb
@@ -12,13 +12,25 @@ module VagrantPlugins
config(:harmony, :push) do
require File.expand_path("../config", __FILE__)
+ init!
Config
end
push(:harmony) do
require File.expand_path("../push", __FILE__)
+ init!
Push
end
+
+ protected
+
+ def self.init!
+ return if defined?(@_init)
+ I18n.load_path << File.expand_path(
+ "templates/locales/TODO.yml", Vagrant.source_root)
+ I18n.reload!
+ @_init = true
+ end
end
end
end
From 170546088080a8f68ba5d9ebcf3e733bef08a14e Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 29 Oct 2014 09:48:18 -0700
Subject: [PATCH 046/203] pushes/harmony: expand dir relative to Vagrantfile
root path
---
plugins/pushes/harmony/push.rb | 2 +-
test/unit/plugins/pushes/harmony/push_test.rb | 17 +++++++++++------
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/plugins/pushes/harmony/push.rb b/plugins/pushes/harmony/push.rb
index 5a3907249..f3906d834 100644
--- a/plugins/pushes/harmony/push.rb
+++ b/plugins/pushes/harmony/push.rb
@@ -27,7 +27,7 @@ module VagrantPlugins
cmd += @config.include.map { |v| ["-include", v] } if !@config.include.empty?
cmd += @config.exclude.map { |v| ["-exclude", v] } if !@config.exclude.empty?
cmd << @config.app
- cmd << @config.dir
+ cmd << File.expand_path(@config.dir, @environment.root_path)
Vagrant::Util::SafeExec.exec(uploader, *cmd.flatten)
end
diff --git a/test/unit/plugins/pushes/harmony/push_test.rb b/test/unit/plugins/pushes/harmony/push_test.rb
index 9b386370c..bf365cc24 100644
--- a/test/unit/plugins/pushes/harmony/push_test.rb
+++ b/test/unit/plugins/pushes/harmony/push_test.rb
@@ -12,13 +12,16 @@ describe VagrantPlugins::HarmonyPush::Push do
end
end
- let(:machine) { double("machine") }
+ let(:environment) { double("environment") }
- subject { described_class.new(machine, config) }
+ subject { described_class.new(environment, config) }
before do
# Stub this right away to avoid real execs
allow(Vagrant::Util::SafeExec).to receive(:exec)
+
+ allow(environment).to receive(:root_path).and_return(
+ File.expand_path("../", __FILE__))
end
describe "#push" do
@@ -47,14 +50,14 @@ describe VagrantPlugins::HarmonyPush::Push do
it "sends the basic flags" do
expect(Vagrant::Util::SafeExec).to receive(:exec).
- with("foo", "-vcs", app, ".")
+ with("foo", "-vcs", app, environment.root_path.to_s)
subject.execute("foo")
end
it "doesn't send VCS if disabled" do
expect(Vagrant::Util::SafeExec).to receive(:exec).
- with("foo", app, ".")
+ with("foo", app, environment.root_path.to_s)
config.vcs = false
subject.execute("foo")
@@ -62,7 +65,8 @@ describe VagrantPlugins::HarmonyPush::Push do
it "sends includes" do
expect(Vagrant::Util::SafeExec).to receive(:exec).
- with("foo", "-vcs", "-include", "foo", "-include", "bar", app, ".")
+ with("foo", "-vcs", "-include", "foo", "-include",
+ "bar", app, environment.root_path.to_s)
config.include = ["foo", "bar"]
subject.execute("foo")
@@ -70,7 +74,8 @@ describe VagrantPlugins::HarmonyPush::Push do
it "sends excludes" do
expect(Vagrant::Util::SafeExec).to receive(:exec).
- with("foo", "-vcs", "-exclude", "foo", "-exclude", "bar", app, ".")
+ with("foo", "-vcs", "-exclude", "foo", "-exclude",
+ "bar", app, environment.root_path.to_s)
config.exclude = ["foo", "bar"]
subject.execute("foo")
From fefaa8da71dddc473e2c4ec45b670a37afa58fc5 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 29 Oct 2014 09:49:37 -0700
Subject: [PATCH 047/203] pushes/harmony: use to_s.strip.empty? to check if app
is set
---
plugins/pushes/harmony/config.rb | 2 +-
test/unit/plugins/pushes/harmony/config_test.rb | 6 ++++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/plugins/pushes/harmony/config.rb b/plugins/pushes/harmony/config.rb
index d9890079e..6698cadec 100644
--- a/plugins/pushes/harmony/config.rb
+++ b/plugins/pushes/harmony/config.rb
@@ -72,7 +72,7 @@ module VagrantPlugins
def validate(machine)
errors = _detected_errors
- if @app == nil || @app == ""
+ if @app.to_s.strip.empty?
errors << I18n.t("push_harmony.errors.config.app_required")
end
diff --git a/test/unit/plugins/pushes/harmony/config_test.rb b/test/unit/plugins/pushes/harmony/config_test.rb
index 0806156e3..17cd4c1fe 100644
--- a/test/unit/plugins/pushes/harmony/config_test.rb
+++ b/test/unit/plugins/pushes/harmony/config_test.rb
@@ -50,6 +50,12 @@ describe VagrantPlugins::HarmonyPush::Config do
assert_invalid
end
+ it "is invalid if blank" do
+ subject.app = " "
+ subject.finalize!
+ assert_invalid
+ end
+
it "is valid if set" do
subject.app = "foo/bar"
subject.finalize!
From 81f748347ecfeaa83fa6ed4ae12c225ddc37eb1d Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 29 Oct 2014 09:52:06 -0700
Subject: [PATCH 048/203] pushes/harmony: fixes from @sethvargo
---
plugins/pushes/harmony/plugin.rb | 4 ++--
plugins/pushes/harmony/push.rb | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/pushes/harmony/plugin.rb b/plugins/pushes/harmony/plugin.rb
index 51630cfbf..331da4b32 100644
--- a/plugins/pushes/harmony/plugin.rb
+++ b/plugins/pushes/harmony/plugin.rb
@@ -11,13 +11,13 @@ module VagrantPlugins
DESC
config(:harmony, :push) do
- require File.expand_path("../config", __FILE__)
+ require_relative "config"
init!
Config
end
push(:harmony) do
- require File.expand_path("../push", __FILE__)
+ require_relative "push"
init!
Push
end
diff --git a/plugins/pushes/harmony/push.rb b/plugins/pushes/harmony/push.rb
index f3906d834..660d3b0fb 100644
--- a/plugins/pushes/harmony/push.rb
+++ b/plugins/pushes/harmony/push.rb
@@ -5,7 +5,7 @@ require "vagrant/util/which"
module VagrantPlugins
module HarmonyPush
class Push < Vagrant.plugin("2", :push)
- UPLOADER_BIN = "harmony-upload"
+ UPLOADER_BIN = "harmony-upload".freeze
def push
uploader = self.uploader_path
From 913dafd3aa48ae9fd8ad3f47636266a4373dd007 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 29 Oct 2014 09:55:43 -0700
Subject: [PATCH 049/203] pushes/harmony: remove unneceessary if
---
plugins/pushes/harmony/push.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/plugins/pushes/harmony/push.rb b/plugins/pushes/harmony/push.rb
index 660d3b0fb..9fd926fee 100644
--- a/plugins/pushes/harmony/push.rb
+++ b/plugins/pushes/harmony/push.rb
@@ -24,8 +24,8 @@ module VagrantPlugins
def execute(uploader)
cmd = []
cmd << "-vcs" if @config.vcs
- cmd += @config.include.map { |v| ["-include", v] } if !@config.include.empty?
- cmd += @config.exclude.map { |v| ["-exclude", v] } if !@config.exclude.empty?
+ cmd += @config.include.map { |v| ["-include", v] }
+ cmd += @config.exclude.map { |v| ["-exclude", v] }
cmd << @config.app
cmd << File.expand_path(@config.dir, @environment.root_path)
Vagrant::Util::SafeExec.exec(uploader, *cmd.flatten)
From 1ac68808e0dce66ee54543eb72afd29db08bf508 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 11 Nov 2014 18:35:20 -0500
Subject: [PATCH 050/203] Add net-sftp as a dep
---
vagrant.gemspec | 1 +
1 file changed, 1 insertion(+)
diff --git a/vagrant.gemspec b/vagrant.gemspec
index 1981493ff..981ce3ed3 100644
--- a/vagrant.gemspec
+++ b/vagrant.gemspec
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
s.add_dependency "hashicorp-checkpoint", "~> 0.1.1"
s.add_dependency "log4r", "~> 1.1.9", "< 1.1.11"
s.add_dependency "net-ssh", ">= 2.6.6", "< 2.10.0"
+ s.add_dependency "net-sftp", "~> 2.1"
s.add_dependency "net-scp", "~> 1.1.0"
s.add_dependency "rb-kqueue", "~> 0.2.0"
s.add_dependency "wdm", "~> 0.1.0"
From f85d96b4253e3c0939583050153a9eb00a5cd42b Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 11 Nov 2014 18:35:27 -0500
Subject: [PATCH 051/203] Add fake_ftp as a development dep
---
vagrant.gemspec | 1 +
1 file changed, 1 insertion(+)
diff --git a/vagrant.gemspec b/vagrant.gemspec
index 981ce3ed3..23931940b 100644
--- a/vagrant.gemspec
+++ b/vagrant.gemspec
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
s.add_development_dependency "rake"
s.add_development_dependency "rspec", "~> 2.14.0"
+ s.add_development_dependency "fake_ftp", "~> 0.1"
# The following block of code determines the files that should be included
# in the gem. It does this by reading all the files in the directory where
From b90253ea8ce6dfab21953934193ae4ac136ddc65 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 11 Nov 2014 18:35:58 -0500
Subject: [PATCH 052/203] Create ftp push config
---
plugins/pushes/ftp/config.rb | 128 +++++++++++++++
plugins/pushes/ftp/locales/en.yml | 9 ++
test/unit/plugins/pushes/ftp/config_test.rb | 171 ++++++++++++++++++++
3 files changed, 308 insertions(+)
create mode 100644 plugins/pushes/ftp/config.rb
create mode 100644 plugins/pushes/ftp/locales/en.yml
create mode 100644 test/unit/plugins/pushes/ftp/config_test.rb
diff --git a/plugins/pushes/ftp/config.rb b/plugins/pushes/ftp/config.rb
new file mode 100644
index 000000000..7ee1961a4
--- /dev/null
+++ b/plugins/pushes/ftp/config.rb
@@ -0,0 +1,128 @@
+module VagrantPlugins
+ module FTPPush
+ class Config < Vagrant.plugin("2", :config)
+ # The (S)FTP host to use.
+ # @return [String]
+ attr_accessor :host
+
+ # The username to use for authentication with the (S)FTP server.
+ # @return [String]
+ attr_accessor :username
+
+ # The password to use for authentication with the (S)FTP server.
+ # @return [String]
+ attr_accessor :password
+
+ # Use passive FTP (default is true).
+ # @return [true, false]
+ attr_accessor :passive
+
+ # Use secure (SFTP) (default is false).
+ # @return [true, false]
+ attr_accessor :secure
+
+ # The root destination on the target system to sync the files (default is
+ # /).
+ # @return [String]
+ attr_accessor :destination
+
+ # Lists of files to include/exclude in what is uploaded. Exclude is
+ # always the last run filter, so if a file is matched in both include
+ # and exclude, it will be excluded.
+ #
+ # The value of the array elements should be a simple file glob relative
+ # to the directory being packaged.
+ # @return [Array]
+ attr_accessor :includes
+ attr_accessor :excludes
+
+ # The base directory with file contents to upload. By default this
+ # is the same directory as the Vagrantfile, but you can specify this
+ # if you have a `src` folder or `bin` folder or some other folder
+ # you want to upload.
+ # @return [String]
+ attr_accessor :dir
+
+ def initialize
+ @host = UNSET_VALUE
+ @username = UNSET_VALUE
+ @password = UNSET_VALUE
+ @passive = UNSET_VALUE
+ @secure = UNSET_VALUE
+ @destination = UNSET_VALUE
+
+ @includes = []
+ @excludes = []
+
+ @dir = UNSET_VALUE
+ end
+
+ def merge(other)
+ super.tap do |result|
+ result.includes = self.includes.dup.concat(other.includes).uniq
+ result.excludes = self.excludes.dup.concat(other.excludes).uniq
+ end
+ end
+
+ def finalize!
+ @host = nil if @host == UNSET_VALUE
+ @username = nil if @username == UNSET_VALUE
+ @password = nil if @password == UNSET_VALUE
+ @passive = true if @passive == UNSET_VALUE
+ @secure = false if @secure == UNSET_VALUE
+ @destination = "/" if @destination == UNSET_VALUE
+ @dir = "." if @dir == UNSET_VALUE
+ end
+
+ def validate(machine)
+ errors = _detected_errors
+
+ if missing?(@host)
+ errors << I18n.t("ftp_push.errors.missing_attribute",
+ attribute: "host",
+ )
+ end
+
+ if missing?(@username)
+ errors << I18n.t("ftp_push.errors.missing_attribute",
+ attribute: "username",
+ )
+ end
+
+ if missing?(@destination)
+ errors << I18n.t("ftp_push.errors.missing_attribute",
+ attribute: "destination",
+ )
+ end
+
+ if missing?(@dir)
+ errors << I18n.t("ftp_push.errors.missing_attribute",
+ attribute: "dir",
+ )
+ end
+
+ { "FTP push" => errors }
+ end
+
+ # Add the filepath to the list of includes
+ # @param [String] filepath
+ def include(filepath)
+ @includes << filepath
+ end
+
+ # Add the filepath to the list of excludes
+ # @param [String] filepath
+ def exclude(filepath)
+ @excludes << filepath
+ end
+
+ private
+
+ # Determine if the given string is "missing" (blank)
+ # @return [true, false]
+ def missing?(obj)
+ obj.to_s.strip.empty?
+ end
+ end
+ end
+end
diff --git a/plugins/pushes/ftp/locales/en.yml b/plugins/pushes/ftp/locales/en.yml
new file mode 100644
index 000000000..dcac3a427
--- /dev/null
+++ b/plugins/pushes/ftp/locales/en.yml
@@ -0,0 +1,9 @@
+en:
+ ftp_push:
+ errors:
+ missing_attribute: |-
+ Missing required attribute '%{attribute}'. The Vagrant FTP Push plugin
+ requires you set this attribute. Please set this attribute in your
+ Vagrantfile, for example:
+
+ push.%{attribute} = "..."
diff --git a/test/unit/plugins/pushes/ftp/config_test.rb b/test/unit/plugins/pushes/ftp/config_test.rb
new file mode 100644
index 000000000..ef5010395
--- /dev/null
+++ b/test/unit/plugins/pushes/ftp/config_test.rb
@@ -0,0 +1,171 @@
+require_relative "../../../base"
+
+require Vagrant.source_root.join("plugins/pushes/ftp/config")
+
+describe VagrantPlugins::FTPPush::Config do
+ include_context "unit"
+
+ before(:all) do
+ I18n.load_path << Vagrant.source_root.join("plugins/pushes/ftp/locales/en.yml")
+ I18n.reload!
+ end
+
+ subject { described_class.new }
+
+ let(:machine) { double("machine") }
+
+ describe "#host" do
+ it "defaults to nil" do
+ subject.finalize!
+ expect(subject.host).to be(nil)
+ end
+ end
+
+ describe "#username" do
+ it "defaults to nil" do
+ subject.finalize!
+ expect(subject.username).to be(nil)
+ end
+ end
+
+ describe "#password" do
+ it "defaults to nil" do
+ subject.finalize!
+ expect(subject.password).to be(nil)
+ end
+ end
+
+ describe "#passive" do
+ it "defaults to true" do
+ subject.finalize!
+ expect(subject.passive).to be(true)
+ end
+ end
+
+ describe "#secure" do
+ it "defaults to false" do
+ subject.finalize!
+ expect(subject.secure).to be(false)
+ end
+ end
+
+ describe "#destination" do
+ it "defaults to /" do
+ subject.finalize!
+ expect(subject.destination).to eq("/")
+ end
+ end
+
+ describe "#dir" do
+ it "defaults to nil" do
+ subject.finalize!
+ expect(subject.dir).to eq(".")
+ end
+ end
+
+ describe "#merge" do
+ context "when includes are given" do
+ let(:one) { described_class.new }
+ let(:two) { described_class.new }
+
+ it "merges the result" do
+ one.includes = %w(a b c)
+ two.includes = %w(c d e)
+ result = one.merge(two)
+ expect(result.includes).to eq(%w(a b c d e))
+ end
+ end
+
+ context "when excludes are given" do
+ let(:one) { described_class.new }
+ let(:two) { described_class.new }
+
+ it "merges the result" do
+ one.excludes = %w(a b c)
+ two.excludes = %w(c d e)
+ result = one.merge(two)
+ expect(result.excludes).to eq(%w(a b c d e))
+ end
+ end
+ end
+
+ describe "#validate" do
+ before do
+ allow(machine).to receive(:env)
+ .and_return(double("env",
+ root_path: "",
+ ))
+
+ subject.host = "ftp.example.com"
+ subject.username = "sethvargo"
+ subject.password = "bacon"
+ subject.destination = "/"
+ subject.dir = "."
+ end
+
+ let(:result) { subject.validate(machine) }
+ let(:errors) { result["FTP push"] }
+
+ context "when the host is missing" do
+ it "returns an error" do
+ subject.host = ""
+ subject.finalize!
+ expect(errors).to include(I18n.t("ftp_push.errors.missing_attribute",
+ attribute: "host",
+ ))
+ end
+ end
+
+ context "when the username is missing" do
+ it "returns an error" do
+ subject.username = ""
+ subject.finalize!
+ expect(errors).to include(I18n.t("ftp_push.errors.missing_attribute",
+ attribute: "username",
+ ))
+ end
+ end
+
+ context "when the password is missing" do
+ it "does not return an error" do
+ subject.password = ""
+ subject.finalize!
+ expect(errors).to be_empty
+ end
+ end
+
+ context "when the destination is missing" do
+ it "returns an error" do
+ subject.destination = ""
+ subject.finalize!
+ expect(errors).to include(I18n.t("ftp_push.errors.missing_attribute",
+ attribute: "destination",
+ ))
+ end
+ end
+
+ context "when the dir is missing" do
+ it "returns an error" do
+ subject.dir = ""
+ subject.finalize!
+ expect(errors).to include(I18n.t("ftp_push.errors.missing_attribute",
+ attribute: "dir",
+ ))
+ end
+ end
+ end
+
+ describe "#include" do
+ it "adds the item to the list" do
+ subject.include("me")
+ expect(subject.includes).to include("me")
+ end
+ end
+
+ describe "#exclude" do
+ it "adds the item to the list" do
+ subject.exclude("not me")
+ expect(subject.excludes).to include("not me")
+ end
+ end
+end
From eb5cecc782ee65507b929f7bf7e0e0a588ab3e27 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 11 Nov 2014 18:36:12 -0500
Subject: [PATCH 053/203] Create ftp push plugin with custom i18n loading
---
plugins/pushes/ftp/plugin.rb | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
create mode 100644 plugins/pushes/ftp/plugin.rb
diff --git a/plugins/pushes/ftp/plugin.rb b/plugins/pushes/ftp/plugin.rb
new file mode 100644
index 000000000..ef333807b
--- /dev/null
+++ b/plugins/pushes/ftp/plugin.rb
@@ -0,0 +1,33 @@
+require "vagrant"
+
+module VagrantPlugins
+ module FTPPush
+ class Plugin < Vagrant.plugin("2")
+ name "ftp"
+ description <<-DESC
+ Deploy to a remote FTP or SFTP server.
+ DESC
+
+ config(:ftp, :push) do
+ require File.expand_path("../config", __FILE__)
+ init!
+ Config
+ end
+
+ push(:ftp) do
+ require File.expand_path("../push", __FILE__)
+ init!
+ Push
+ end
+
+ protected
+
+ def self.init!
+ return if defined?(@_init)
+ I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
+ I18n.reload!
+ @_init = true
+ end
+ end
+ end
+end
From 80851a887ff5d55e832539d7ad605a0356ed0b7e Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 11 Nov 2014 18:36:30 -0500
Subject: [PATCH 054/203] Create an Adapter to bridge the APIs between SFTP and
FTP libraries
---
plugins/pushes/ftp/adapter.rb | 107 ++++++++++++++++++
test/unit/plugins/pushes/ftp/adapter_test.rb | 111 +++++++++++++++++++
2 files changed, 218 insertions(+)
create mode 100644 plugins/pushes/ftp/adapter.rb
create mode 100644 test/unit/plugins/pushes/ftp/adapter_test.rb
diff --git a/plugins/pushes/ftp/adapter.rb b/plugins/pushes/ftp/adapter.rb
new file mode 100644
index 000000000..f370d411f
--- /dev/null
+++ b/plugins/pushes/ftp/adapter.rb
@@ -0,0 +1,107 @@
+module VagrantPlugins
+ module FTPPush
+ class Adapter
+ attr_reader :host
+ attr_reader :port
+ attr_reader :username
+ attr_reader :password
+ attr_reader :options
+ attr_reader :server
+
+ def initialize(host, username, password, options = {})
+ @host, @port = parse_host(host)
+ @username = username
+ @password = password
+ @options = options
+ @server = nil
+ end
+
+ # Parse the host into it's url and port parts.
+ # @return [Array]
+ def parse_host(host)
+ if host.include?(":")
+ split = host.split(":", 2)
+ [split[0], split[1].to_i]
+ else
+ [host, default_port]
+ end
+ end
+
+ def default_port
+ raise NotImplementedError
+ end
+
+ def connect(&block)
+ raise NotImplementedError
+ end
+
+ def upload(local, remote)
+ raise NotImplementedError
+ end
+ end
+
+ #
+ # The FTP Adapter
+ #
+ class FTPAdapter < Adapter
+ def initialize(*)
+ require "net/ftp"
+ super
+ end
+
+ def default_port
+ 20
+ end
+
+ def connect(&block)
+ @server = Net::FTP.new
+ @server.passive = options.fetch(:passive, true)
+ @server.connect(host, port)
+ @server.login(username, password)
+
+ begin
+ yield self
+ ensure
+ @server.close
+ end
+ end
+
+ def upload(local, remote)
+ parent = File.dirname(remote)
+
+ # Create the parent directory if it does not exist
+ if !@server.list("/").any? { |f| f.start_with?(parent) }
+ @server.mkdir(parent)
+ end
+
+ # Upload the file
+ @server.putbinaryfile(local, remote)
+ end
+ end
+
+ #
+ # The SFTP Adapter
+ #
+ class SFTPAdapter < Adapter
+ def initialize(*)
+ require "net/sftp"
+ super
+ end
+
+ def default_port
+ 22
+ end
+
+ def connect(&block)
+ Net::SFTP.start(@host, @username, password: @password, port: @port) do |server|
+ @server = server
+ yield self
+ end
+ end
+
+ def upload(local, remote)
+ @server.upload!(local, remote, mkdir: true)
+ end
+ end
+ end
+end
diff --git a/test/unit/plugins/pushes/ftp/adapter_test.rb b/test/unit/plugins/pushes/ftp/adapter_test.rb
new file mode 100644
index 000000000..54bacc1d1
--- /dev/null
+++ b/test/unit/plugins/pushes/ftp/adapter_test.rb
@@ -0,0 +1,111 @@
+require_relative "../../../base"
+require "fake_ftp"
+
+require Vagrant.source_root.join("plugins/pushes/ftp/adapter")
+
+describe VagrantPlugins::FTPPush::Adapter do
+ include_context "unit"
+
+ subject do
+ described_class.new("127.0.0.1:2345", "sethvargo", "bacon",
+ foo: "bar",
+ )
+ end
+
+ describe "#initialize" do
+ it "sets the instance variables" do
+ expect(subject.host).to eq("127.0.0.1")
+ expect(subject.port).to eq(2345)
+ expect(subject.username).to eq("sethvargo")
+ expect(subject.password).to eq("bacon")
+ expect(subject.options).to eq(foo: "bar")
+ expect(subject.server).to be(nil)
+ end
+ end
+
+ describe "#parse_host" do
+ it "has a default value" do
+ allow(subject).to receive(:default_port)
+ .and_return(5555)
+
+ result = subject.parse_host("127.0.0.1")
+ expect(result[0]).to eq("127.0.0.1")
+ expect(result[1]).to eq(5555)
+ end
+ end
+end
+
+describe VagrantPlugins::FTPPush::FTPAdapter do
+ include_context "unit"
+
+ before(:all) do
+ @server = FakeFtp::Server.new(21212, 21213)
+ @server.start
+ end
+
+ after(:all) { @server.stop }
+
+ let(:server) { @server }
+
+ before { server.reset }
+
+ subject do
+ described_class.new("127.0.0.1:#{server.port}", "sethvargo", "bacon")
+ end
+
+ describe "#default_port" do
+ it "is 20" do
+ expect(subject.default_port).to eq(20)
+ end
+ end
+
+ describe "#upload" do
+ before do
+ @dir = Dir.mktmpdir
+ FileUtils.touch("#{@dir}/file")
+ end
+
+ after do
+ FileUtils.rm_rf(@dir)
+ end
+
+ it "uploads the file" do
+ subject.connect do |ftp|
+ ftp.upload("#{@dir}/file", "/file")
+ end
+
+ expect(server.files).to include("file")
+ end
+
+ it "uploads in passive mode" do
+ subject.options[:passive] = true
+ subject.connect do |ftp|
+ ftp.upload("#{@dir}/file", "/file")
+ end
+
+ expect(server.file("file")).to be_passive
+ end
+ end
+end
+
+describe VagrantPlugins::FTPPush::SFTPAdapter do
+ include_context "unit"
+
+ subject do
+ described_class.new("127.0.0.1:2345", "sethvargo", "bacon",
+ foo: "bar",
+ )
+ end
+
+ describe "#default_port" do
+ it "is 22" do
+ expect(subject.default_port).to eq(22)
+ end
+ end
+
+ describe "#upload" do
+ it "uploads the file" do
+ pending "a way to mock an SFTP server"
+ end
+ end
+end
From 8aaf5dc5786252f0f3435402fe9d8f1f0faa5072 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 11 Nov 2014 18:36:42 -0500
Subject: [PATCH 055/203] Add the FTP push
---
plugins/pushes/ftp/push.rb | 116 ++++++++
test/unit/plugins/pushes/ftp/push_test.rb | 313 ++++++++++++++++++++++
2 files changed, 429 insertions(+)
create mode 100644 plugins/pushes/ftp/push.rb
create mode 100644 test/unit/plugins/pushes/ftp/push_test.rb
diff --git a/plugins/pushes/ftp/push.rb b/plugins/pushes/ftp/push.rb
new file mode 100644
index 000000000..3cf4169a0
--- /dev/null
+++ b/plugins/pushes/ftp/push.rb
@@ -0,0 +1,116 @@
+require "net/ftp"
+require "pathname"
+
+require_relative "adapter"
+
+module VagrantPlugins
+ module FTPPush
+ class Push < Vagrant.plugin("2", :push)
+ IGNORED_FILES = %w(. ..).freeze
+
+ def push
+ # Grab files early so if there's an exception or issue, we don't have to
+ # wait and close the (S)FTP connection as well
+ files = Hash[*all_files.flat_map do |file|
+ relative_path = relative_path_for(file, config.dir)
+ destination = File.expand_path(File.join(config.destination, relative_path))
+ [file, destination]
+ end]
+
+ connect do |ftp|
+ files.each do |local, remote|
+ ftp.upload(local, remote)
+ end
+ end
+ end
+
+ # Helper method for creating the FTP or SFTP connection.
+ # @yield [Adapter]
+ def connect(&block)
+ klass = config.secure ? SFTPAdapter : FTPAdapter
+ ftp = klass.new(config.host, config.username, config.password,
+ passive: config.passive)
+ ftp.connect(&block)
+ end
+
+ # Parse the host into it's url and port parts.
+ # @return [Array]
+ def parse_host(host)
+ if host.include?(":")
+ host.split(":", 2)
+ else
+ [host, "22"]
+ end
+ end
+
+ # The list of all files that should be pushed by this push. This method
+ # only returns **files**, not folders or symlinks!
+ # @return [Array]
+ def all_files
+ files = glob("#{config.dir}/**/*") + includes_files
+ filter_excludes!(files, config.excludes)
+ files.reject! { |f| !File.file?(f) }
+ files
+ end
+
+ # The list of files to include in addition to those specified in `dir`.
+ # @return [Array]
+ def includes_files
+ includes = config.includes.flat_map do |i|
+ path = absolute_path_for(i, config.dir)
+ [path, "#{path}/**/*"]
+ end
+
+ glob("{#{includes.join(",")}}")
+ end
+
+ # Filter the excludes out of the given list. This method modifies the
+ # given list in memory!
+ #
+ # @param [Array] list
+ # the filepaths
+ # @param [Array] excludes
+ # the exclude patterns or files
+ def filter_excludes!(list, excludes)
+ excludes = Array(excludes).flat_map { |e| [e, "#{e}/*"] }
+ list.reject! do |file|
+ basename = relative_path_for(file, config.dir)
+
+ # Handle the special case where the file is outside of the working
+ # directory...
+ if basename.start_with?("../")
+ basename = file
+ end
+
+ excludes.any? { |e| File.fnmatch?(e, basename, File::FNM_DOTMATCH) }
+ end
+ end
+
+ # Get the list of files that match the given pattern.
+ # @return [Array]
+ def glob(pattern)
+ Dir.glob(pattern, File::FNM_DOTMATCH).sort.reject do |file|
+ IGNORED_FILES.include?(File.basename(file))
+ end
+ end
+
+ # The absolute path to the given `path` and `parent`, unless the given
+ # path is absolute.
+ # @return [String]
+ def absolute_path_for(path, parent)
+ path = Pathname.new(path)
+ return path if path.absolute?
+ File.expand_path(path, parent)
+ end
+
+ # The relative path from the given `parent`. If files exist on another
+ # device, this will probably blow up.
+ # @return [String]
+ def relative_path_for(path, parent)
+ Pathname.new(path).relative_path_from(Pathname.new(parent)).to_s
+ rescue ArgumentError
+ return path
+ end
+ end
+ end
+end
diff --git a/test/unit/plugins/pushes/ftp/push_test.rb b/test/unit/plugins/pushes/ftp/push_test.rb
new file mode 100644
index 000000000..ca8ee2752
--- /dev/null
+++ b/test/unit/plugins/pushes/ftp/push_test.rb
@@ -0,0 +1,313 @@
+require_relative "../../../base"
+require "fake_ftp"
+
+require Vagrant.source_root.join("plugins/pushes/ftp/push")
+
+describe VagrantPlugins::FTPPush::Push do
+ include_context "unit"
+
+ let(:env) { isolated_environment }
+ let(:config) do
+ double("config",
+ host: "127.0.0.1:21212",
+ username: "sethvargo",
+ password: "bacon",
+ passive: false,
+ secure: false,
+ destination: "/var/www/site",
+ )
+ end
+
+ subject { described_class.new(env, config) }
+
+ describe "#push" do
+ before(:all) do
+ @server = FakeFtp::Server.new(21212, 21213)
+ @server.start
+
+ @dir = Dir.mktmpdir
+
+ FileUtils.touch("#{@dir}/.hidden.rb")
+ FileUtils.touch("#{@dir}/application.rb")
+ FileUtils.touch("#{@dir}/config.rb")
+ FileUtils.touch("#{@dir}/Gemfile")
+ FileUtils.touch("#{@dir}/data.txt")
+ FileUtils.mkdir("#{@dir}/empty_folder")
+ end
+
+ after(:all) do
+ FileUtils.rm_rf(@dir)
+ @server.stop
+ end
+
+ let(:server) { @server }
+
+ before do
+ allow(config).to receive(:dir)
+ .and_return(@dir)
+
+ allow(config).to receive(:includes)
+ .and_return([])
+
+ allow(config).to receive(:excludes)
+ .and_return(%w(*.rb))
+ end
+
+
+ it "pushes the files to the server" do
+ subject.push
+ expect(server.files).to eq(%w(Gemfile data.txt))
+ end
+ end
+
+ describe "#connect" do
+ before do
+ allow_any_instance_of(VagrantPlugins::FTPPush::FTPAdapter)
+ .to receive(:connect)
+ .and_yield(:ftp)
+ allow_any_instance_of(VagrantPlugins::FTPPush::SFTPAdapter)
+ .to receive(:connect)
+ .and_yield(:sftp)
+ end
+
+ context "when secure is requested" do
+ before do
+ allow(config).to receive(:secure)
+ .and_return(true)
+ end
+
+ it "yields a new SFTPAdapter" do
+ expect { |b| subject.connect(&b) }.to yield_with_args(:sftp)
+ end
+ end
+
+ context "when secure is not requested" do
+ before do
+ allow(config).to receive(:secure)
+ .and_return(false)
+ end
+
+ it "yields a new FTPAdapter" do
+ expect { |b| subject.connect(&b) }.to yield_with_args(:ftp)
+ end
+ end
+ end
+
+ describe "#parse_host" do
+ let(:result) { subject.parse_host(host) }
+
+ context "when no port is given" do
+ let(:host) { "127.0.0.1" }
+
+ it "returns the url and port 22" do
+ expect(result).to eq(["127.0.0.1", "22"])
+ end
+ end
+
+ context "when a port is given" do
+ let(:host) { "127.0.0.1:23456" }
+
+ it "returns the url and port 23456" do
+ expect(result).to eq(["127.0.0.1", "23456"])
+ end
+ end
+
+ context "when more than more port is given" do
+ let(:host) { "127.0.0.1:22:33:44" }
+
+ it "returns the url and everything after" do
+ expect(result).to eq(["127.0.0.1", "22:33:44"])
+ end
+ end
+ end
+
+ describe "#all_files" do
+ before(:all) do
+ @dir = Dir.mktmpdir
+
+ FileUtils.touch("#{@dir}/.hidden.rb")
+ FileUtils.touch("#{@dir}/application.rb")
+ FileUtils.touch("#{@dir}/config.rb")
+ FileUtils.touch("#{@dir}/Gemfile")
+ FileUtils.mkdir("#{@dir}/empty_folder")
+ FileUtils.mkdir("#{@dir}/folder")
+ FileUtils.mkdir("#{@dir}/folder/.git")
+ FileUtils.touch("#{@dir}/folder/.git/config")
+ FileUtils.touch("#{@dir}/folder/server.rb")
+ end
+
+ after(:all) do
+ FileUtils.rm_rf(@dir)
+ end
+
+ let(:files) do
+ subject.all_files.map do |file|
+ file.sub("#{@dir}/", "")
+ end
+ end
+
+ before do
+ allow(config).to receive(:dir)
+ .and_return(@dir)
+
+ allow(config).to receive(:includes)
+ .and_return(%w(not_a_file.rb still_not_a_file.rb))
+
+ allow(config).to receive(:excludes)
+ .and_return(%w(*.rb))
+ end
+
+ it "returns the list of real files + includes, without excludes" do
+ expect(files).to eq(%w(
+ Gemfile
+ folder/.git/config
+ ))
+ end
+ end
+
+ describe "includes_files" do
+ before(:all) do
+ @dir = Dir.mktmpdir
+
+ FileUtils.touch("#{@dir}/.hidden.rb")
+ FileUtils.touch("#{@dir}/application.rb")
+ FileUtils.touch("#{@dir}/config.rb")
+ FileUtils.touch("#{@dir}/Gemfile")
+ FileUtils.mkdir("#{@dir}/folder")
+ FileUtils.mkdir("#{@dir}/folder/.git")
+ FileUtils.touch("#{@dir}/folder/.git/config")
+ FileUtils.touch("#{@dir}/folder/server.rb")
+ end
+
+ after(:all) do
+ FileUtils.rm_rf(@dir)
+ end
+
+ let(:files) do
+ subject.includes_files.map do |file|
+ file.sub("#{@dir}/", "")
+ end
+ end
+
+ before do
+ allow(config).to receive(:dir)
+ .and_return(@dir)
+ end
+
+ def set_includes(value)
+ allow(config).to receive(:includes)
+ .and_return(value)
+ end
+
+ it "includes the file" do
+ set_includes(["Gemfile"])
+ expect(files).to eq(%w(
+ Gemfile
+ ))
+ end
+
+ it "includes the files that are subdirectories" do
+ set_includes(["folder"])
+ expect(files).to eq(%w(
+ folder
+ folder/.git
+ folder/.git/config
+ folder/server.rb
+ ))
+ end
+
+ it "includes files that match a pattern" do
+ set_includes(["*.rb"])
+ expect(files).to eq(%w(
+ .hidden.rb
+ application.rb
+ config.rb
+ ))
+ end
+ end
+
+ describe "#filter_excludes" do
+ let(:dir) { "/root/dir" }
+
+ let(:list) do
+ %W(
+ #{dir}/.hidden.rb
+ #{dir}/application.rb
+ #{dir}/config.rb
+ #{dir}/Gemfile
+ #{dir}/folder
+ #{dir}/folder/.git
+ #{dir}/folder/.git/config
+ #{dir}/folder/server.rb
+
+ /path/outside/you.rb
+ /path/outside/me.rb
+ /path/outside/folder/bacon.rb
+ )
+ end
+
+ before do
+ allow(config).to receive(:dir)
+ .and_return(dir)
+ end
+
+ it "excludes files" do
+ subject.filter_excludes!(list, %w(*.rb))
+
+ expect(list).to eq(%W(
+ #{dir}/Gemfile
+ #{dir}/folder
+ #{dir}/folder/.git
+ #{dir}/folder/.git/config
+ ))
+ end
+
+ it "excludes files in a directory" do
+ subject.filter_excludes!(list, %w(folder))
+
+ expect(list).to eq(%W(
+ #{dir}/.hidden.rb
+ #{dir}/application.rb
+ #{dir}/config.rb
+ #{dir}/Gemfile
+
+ /path/outside/you.rb
+ /path/outside/me.rb
+ /path/outside/folder/bacon.rb
+ ))
+ end
+
+ it "excludes specific files in a directory" do
+ subject.filter_excludes!(list, %w(/path/outside/folder/*.rb))
+
+ expect(list).to eq(%W(
+ #{dir}/.hidden.rb
+ #{dir}/application.rb
+ #{dir}/config.rb
+ #{dir}/Gemfile
+ #{dir}/folder
+ #{dir}/folder/.git
+ #{dir}/folder/.git/config
+ #{dir}/folder/server.rb
+
+ /path/outside/you.rb
+ /path/outside/me.rb
+ ))
+ end
+
+ it "excludes files outside the #dir" do
+ subject.filter_excludes!(list, %w(/path/outside))
+
+ expect(list).to eq(%W(
+ #{dir}/.hidden.rb
+ #{dir}/application.rb
+ #{dir}/config.rb
+ #{dir}/Gemfile
+ #{dir}/folder
+ #{dir}/folder/.git
+ #{dir}/folder/.git/config
+ #{dir}/folder/server.rb
+ ))
+ end
+ end
+end
From c8bdf53c7ebed13c8942ae0246cf4be9a7e3cf79 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 11 Nov 2014 18:58:02 -0500
Subject: [PATCH 056/203] Rename push environment to env
---
lib/vagrant/plugin/v2/push.rb | 8 ++++----
plugins/pushes/harmony/push.rb | 12 ++++++------
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/lib/vagrant/plugin/v2/push.rb b/lib/vagrant/plugin/v2/push.rb
index 002479b33..f8bc15d53 100644
--- a/lib/vagrant/plugin/v2/push.rb
+++ b/lib/vagrant/plugin/v2/push.rb
@@ -2,16 +2,16 @@ module Vagrant
module Plugin
module V2
class Push
- attr_reader :environment
+ attr_reader :env
attr_reader :config
# Initializes the pusher with the given environment the push
# configuration.
#
- # @param [environment] environment
+ # @param [Environment] env
# @param [Object] config Push configuration
- def initialize(environment, config)
- @environment = environment
+ def initialize(env, config)
+ @env = env
@config = config
end
diff --git a/plugins/pushes/harmony/push.rb b/plugins/pushes/harmony/push.rb
index 9fd926fee..022c5db07 100644
--- a/plugins/pushes/harmony/push.rb
+++ b/plugins/pushes/harmony/push.rb
@@ -23,11 +23,11 @@ module VagrantPlugins
# if we're on a system that doesn't support exec, so handle that properly.
def execute(uploader)
cmd = []
- cmd << "-vcs" if @config.vcs
- cmd += @config.include.map { |v| ["-include", v] }
- cmd += @config.exclude.map { |v| ["-exclude", v] }
- cmd << @config.app
- cmd << File.expand_path(@config.dir, @environment.root_path)
+ cmd << "-vcs" if config.vcs
+ cmd += config.include.map { |v| ["-include", v] }
+ cmd += config.exclude.map { |v| ["-exclude", v] }
+ cmd << config.app
+ cmd << File.expand_path(config.dir, env.root_path)
Vagrant::Util::SafeExec.exec(uploader, *cmd.flatten)
end
@@ -37,7 +37,7 @@ module VagrantPlugins
# @return [String]
def uploader_path
# Determine the uploader path
- uploader = @config.uploader_path
+ uploader = config.uploader_path
if uploader
return uploader
end
From ed605c9aacc82b441a264c75e931d7b62328ff1c Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 12 Nov 2014 15:49:55 -0500
Subject: [PATCH 057/203] Rename Harmony to Atlas, minor config changes
---
plugins/pushes/{harmony => atlas}/config.rb | 55 +++++--
plugins/pushes/{harmony => atlas}/errors.rb | 4 +-
plugins/pushes/atlas/locales/en.yml | 11 ++
plugins/pushes/{harmony => atlas}/plugin.rb | 10 +-
plugins/pushes/{harmony => atlas}/push.rb | 8 +-
test/unit/plugins/pushes/atlas/config_test.rb | 135 ++++++++++++++++++
.../pushes/{harmony => atlas}/push_test.rb | 35 ++---
.../plugins/pushes/harmony/config_test.rb | 91 ------------
8 files changed, 215 insertions(+), 134 deletions(-)
rename plugins/pushes/{harmony => atlas}/config.rb (63%)
rename plugins/pushes/{harmony => atlas}/errors.rb (74%)
create mode 100644 plugins/pushes/atlas/locales/en.yml
rename plugins/pushes/{harmony => atlas}/plugin.rb (79%)
rename plugins/pushes/{harmony => atlas}/push.rb (88%)
create mode 100644 test/unit/plugins/pushes/atlas/config_test.rb
rename test/unit/plugins/pushes/{harmony => atlas}/push_test.rb (73%)
delete mode 100644 test/unit/plugins/pushes/harmony/config_test.rb
diff --git a/plugins/pushes/harmony/config.rb b/plugins/pushes/atlas/config.rb
similarity index 63%
rename from plugins/pushes/harmony/config.rb
rename to plugins/pushes/atlas/config.rb
index 6698cadec..71b40e299 100644
--- a/plugins/pushes/harmony/config.rb
+++ b/plugins/pushes/atlas/config.rb
@@ -1,5 +1,5 @@
module VagrantPlugins
- module HarmonyPush
+ module AtlasPush
class Config < Vagrant.plugin("2", :config)
# The name of the application to push to. This will be created (with
# user confirmation) if it doesn't already exist.
@@ -23,8 +23,8 @@ module VagrantPlugins
# to the directory being packaged.
#
# @return [Array]
- attr_accessor :include
- attr_accessor :exclude
+ attr_accessor :includes
+ attr_accessor :excludes
# If set to true, Vagrant will automatically use VCS data to determine
# the files to upload. As a caveat: uncommitted changes will not be
@@ -45,20 +45,15 @@ module VagrantPlugins
@app = UNSET_VALUE
@dir = UNSET_VALUE
@vcs = UNSET_VALUE
- @include = []
- @exclude = []
+ @includes = []
+ @excludes = []
@uploader_path = UNSET_VALUE
end
def merge(other)
super.tap do |result|
- inc = self.include.dup
- inc.concat(other.include)
- result.include = inc
-
- exc = self.exclude.dup
- exc.concat(other.exclude)
- result.exclude = exc
+ result.includes = self.includes.dup.concat(other.includes).uniq
+ result.excludes = self.excludes.dup.concat(other.excludes).uniq
end
end
@@ -72,11 +67,41 @@ module VagrantPlugins
def validate(machine)
errors = _detected_errors
- if @app.to_s.strip.empty?
- errors << I18n.t("push_harmony.errors.config.app_required")
+ if missing?(@app)
+ errors << I18n.t("atlas_push.errors.missing_attribute",
+ attribute: "app",
+ )
end
- { "Harmony push" => errors }
+ if missing?(@dir)
+ errors << I18n.t("atlas_push.errors.missing_attribute",
+ attribute: "dir",
+ )
+ end
+
+ { "Atlas push" => errors }
+ end
+
+ # Add the filepath to the list of includes
+ # @param [String] filepath
+ def include(filepath)
+ @includes << filepath
+ end
+ alias_method :include=, :include
+
+ # Add the filepath to the list of excludes
+ # @param [String] filepath
+ def exclude(filepath)
+ @excludes << filepath
+ end
+ alias_method :exclude=, :exclude
+
+ private
+
+ # Determine if the given string is "missing" (blank)
+ # @return [true, false]
+ def missing?(obj)
+ obj.to_s.strip.empty?
end
end
end
diff --git a/plugins/pushes/harmony/errors.rb b/plugins/pushes/atlas/errors.rb
similarity index 74%
rename from plugins/pushes/harmony/errors.rb
rename to plugins/pushes/atlas/errors.rb
index 9eb590ff3..6fee42698 100644
--- a/plugins/pushes/harmony/errors.rb
+++ b/plugins/pushes/atlas/errors.rb
@@ -1,8 +1,8 @@
module VagrantPlugins
- module HarmonyPush
+ module AtlasPush
module Errors
class Error < Vagrant::Errors::VagrantError
- error_namespace("harmony_push.errors")
+ error_namespace("atlas_push.errors")
end
class UploaderNotFound < Error
diff --git a/plugins/pushes/atlas/locales/en.yml b/plugins/pushes/atlas/locales/en.yml
new file mode 100644
index 000000000..745e33bd2
--- /dev/null
+++ b/plugins/pushes/atlas/locales/en.yml
@@ -0,0 +1,11 @@
+en:
+ atlas_push:
+ errors:
+ missing_attribute: |-
+ Missing required attribute '%{attribute}'. The Vagrant Atlas Push plugin
+ requires you set this attribute. Please set this attribute in your
+ Vagrantfile, for example:
+
+ config.push.define "atlas" do |push|
+ push.%{attribute} = "..."
+ end
diff --git a/plugins/pushes/harmony/plugin.rb b/plugins/pushes/atlas/plugin.rb
similarity index 79%
rename from plugins/pushes/harmony/plugin.rb
rename to plugins/pushes/atlas/plugin.rb
index 331da4b32..b5c213a80 100644
--- a/plugins/pushes/harmony/plugin.rb
+++ b/plugins/pushes/atlas/plugin.rb
@@ -1,22 +1,22 @@
require "vagrant"
module VagrantPlugins
- module HarmonyPush
+ module AtlasPush
autoload :Errors, File.expand_path("../errors", __FILE__)
class Plugin < Vagrant.plugin("2")
- name "harmony"
+ name "atlas"
description <<-DESC
- Deploy using HashiCorp's Harmony service.
+ Deploy using HashiCorp's Atlas service.
DESC
- config(:harmony, :push) do
+ config(:atlas, :push) do
require_relative "config"
init!
Config
end
- push(:harmony) do
+ push(:atlas) do
require_relative "push"
init!
Push
diff --git a/plugins/pushes/harmony/push.rb b/plugins/pushes/atlas/push.rb
similarity index 88%
rename from plugins/pushes/harmony/push.rb
rename to plugins/pushes/atlas/push.rb
index 022c5db07..7dd64a358 100644
--- a/plugins/pushes/harmony/push.rb
+++ b/plugins/pushes/atlas/push.rb
@@ -3,9 +3,9 @@ require "vagrant/util/subprocess"
require "vagrant/util/which"
module VagrantPlugins
- module HarmonyPush
+ module AtlasPush
class Push < Vagrant.plugin("2", :push)
- UPLOADER_BIN = "harmony-upload".freeze
+ UPLOADER_BIN = "atlas-upload".freeze
def push
uploader = self.uploader_path
@@ -24,8 +24,8 @@ module VagrantPlugins
def execute(uploader)
cmd = []
cmd << "-vcs" if config.vcs
- cmd += config.include.map { |v| ["-include", v] }
- cmd += config.exclude.map { |v| ["-exclude", v] }
+ cmd += config.includes.map { |v| ["-include", v] }
+ cmd += config.excludes.map { |v| ["-exclude", v] }
cmd << config.app
cmd << File.expand_path(config.dir, env.root_path)
Vagrant::Util::SafeExec.exec(uploader, *cmd.flatten)
diff --git a/test/unit/plugins/pushes/atlas/config_test.rb b/test/unit/plugins/pushes/atlas/config_test.rb
new file mode 100644
index 000000000..87411c472
--- /dev/null
+++ b/test/unit/plugins/pushes/atlas/config_test.rb
@@ -0,0 +1,135 @@
+require_relative "../../../base"
+
+require Vagrant.source_root.join("plugins/pushes/atlas/config")
+
+describe VagrantPlugins::AtlasPush::Config do
+ include_context "unit"
+
+ before(:all) do
+ I18n.load_path << Vagrant.source_root.join("plugins/pushes/atlas/locales/en.yml")
+ I18n.reload!
+ end
+
+ let(:machine) { double("machine") }
+
+ describe "#app" do
+ it "defaults to nil" do
+ subject.finalize!
+ expect(subject.app).to be(nil)
+ end
+ end
+
+ describe "#dir" do
+ it "defaults to ." do
+ subject.finalize!
+ expect(subject.dir).to eq(".")
+ end
+ end
+
+ describe "#vcs" do
+ it "defaults to true" do
+ subject.finalize!
+ expect(subject.vcs).to be(true)
+ end
+ end
+
+ describe "#uploader_path" do
+ it "defaults to nil" do
+ subject.finalize!
+ expect(subject.uploader_path).to be(nil)
+ end
+ end
+
+ describe "#validate" do
+ before do
+ allow(machine).to receive(:env)
+ .and_return(double("env",
+ root_path: "",
+ ))
+
+ subject.app = "sethvargo/bacon"
+ subject.dir = "."
+ subject.vcs = true
+ subject.uploader_path = "uploader"
+ end
+
+ let(:result) { subject.validate(machine) }
+ let(:errors) { result["Atlas push"] }
+
+ context "when the app is missing" do
+ it "returns an error" do
+ subject.app = ""
+ subject.finalize!
+ expect(errors).to include(I18n.t("atlas_push.errors.missing_attribute",
+ attribute: "app",
+ ))
+ end
+ end
+
+ context "when the dir is missing" do
+ it "returns an error" do
+ subject.dir = ""
+ subject.finalize!
+ expect(errors).to include(I18n.t("atlas_push.errors.missing_attribute",
+ attribute: "dir",
+ ))
+ end
+ end
+
+ context "when the vcs is missing" do
+ it "does not return an error" do
+ subject.vcs = ""
+ subject.finalize!
+ expect(errors).to be_empty
+ end
+ end
+
+ context "when the uploader_path is missing" do
+ it "returns an error" do
+ subject.uploader_path = ""
+ subject.finalize!
+ expect(errors).to be_empty
+ end
+ end
+ end
+
+ describe "#merge" do
+ context "when includes are given" do
+ let(:one) { described_class.new }
+ let(:two) { described_class.new }
+
+ it "merges the result" do
+ one.includes = %w(a b c)
+ two.includes = %w(c d e)
+ result = one.merge(two)
+ expect(result.includes).to eq(%w(a b c d e))
+ end
+ end
+
+ context "when excludes are given" do
+ let(:one) { described_class.new }
+ let(:two) { described_class.new }
+
+ it "merges the result" do
+ one.excludes = %w(a b c)
+ two.excludes = %w(c d e)
+ result = one.merge(two)
+ expect(result.excludes).to eq(%w(a b c d e))
+ end
+ end
+ end
+
+ describe "#include" do
+ it "adds the item to the list" do
+ subject.include("me")
+ expect(subject.includes).to include("me")
+ end
+ end
+
+ describe "#exclude" do
+ it "adds the item to the list" do
+ subject.exclude("not me")
+ expect(subject.excludes).to include("not me")
+ end
+ end
+end
diff --git a/test/unit/plugins/pushes/harmony/push_test.rb b/test/unit/plugins/pushes/atlas/push_test.rb
similarity index 73%
rename from test/unit/plugins/pushes/harmony/push_test.rb
rename to test/unit/plugins/pushes/atlas/push_test.rb
index bf365cc24..40bb9b8d1 100644
--- a/test/unit/plugins/pushes/harmony/push_test.rb
+++ b/test/unit/plugins/pushes/atlas/push_test.rb
@@ -1,27 +1,28 @@
require_relative "../../../base"
-require Vagrant.source_root.join("plugins/pushes/harmony/config")
-require Vagrant.source_root.join("plugins/pushes/harmony/push")
+require Vagrant.source_root.join("plugins/pushes/atlas/config")
+require Vagrant.source_root.join("plugins/pushes/atlas/push")
-describe VagrantPlugins::HarmonyPush::Push do
+describe VagrantPlugins::AtlasPush::Push do
include_context "unit"
+ let(:env) do
+ double("env",
+ root_path: File.expand_path("..", __FILE__)
+ )
+ end
+
let(:config) do
- VagrantPlugins::HarmonyPush::Config.new.tap do |c|
+ VagrantPlugins::AtlasPush::Config.new.tap do |c|
c.finalize!
end
end
- let(:environment) { double("environment") }
-
- subject { described_class.new(environment, config) }
+ subject { described_class.new(env, config) }
before do
# Stub this right away to avoid real execs
allow(Vagrant::Util::SafeExec).to receive(:exec)
-
- allow(environment).to receive(:root_path).and_return(
- File.expand_path("../", __FILE__))
end
describe "#push" do
@@ -37,7 +38,7 @@ describe VagrantPlugins::HarmonyPush::Push do
expect(subject).to receive(:uploader_path).and_return(nil)
expect { subject.push }.to raise_error(
- VagrantPlugins::HarmonyPush::Errors::UploaderNotFound)
+ VagrantPlugins::AtlasPush::Errors::UploaderNotFound)
end
end
@@ -50,14 +51,14 @@ describe VagrantPlugins::HarmonyPush::Push do
it "sends the basic flags" do
expect(Vagrant::Util::SafeExec).to receive(:exec).
- with("foo", "-vcs", app, environment.root_path.to_s)
+ with("foo", "-vcs", app, env.root_path.to_s)
subject.execute("foo")
end
it "doesn't send VCS if disabled" do
expect(Vagrant::Util::SafeExec).to receive(:exec).
- with("foo", app, environment.root_path.to_s)
+ with("foo", app, env.root_path.to_s)
config.vcs = false
subject.execute("foo")
@@ -66,18 +67,18 @@ describe VagrantPlugins::HarmonyPush::Push do
it "sends includes" do
expect(Vagrant::Util::SafeExec).to receive(:exec).
with("foo", "-vcs", "-include", "foo", "-include",
- "bar", app, environment.root_path.to_s)
+ "bar", app, env.root_path.to_s)
- config.include = ["foo", "bar"]
+ config.includes = ["foo", "bar"]
subject.execute("foo")
end
it "sends excludes" do
expect(Vagrant::Util::SafeExec).to receive(:exec).
with("foo", "-vcs", "-exclude", "foo", "-exclude",
- "bar", app, environment.root_path.to_s)
+ "bar", app, env.root_path.to_s)
- config.exclude = ["foo", "bar"]
+ config.excludes = ["foo", "bar"]
subject.execute("foo")
end
end
diff --git a/test/unit/plugins/pushes/harmony/config_test.rb b/test/unit/plugins/pushes/harmony/config_test.rb
deleted file mode 100644
index 17cd4c1fe..000000000
--- a/test/unit/plugins/pushes/harmony/config_test.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-require_relative "../../../base"
-
-require Vagrant.source_root.join("plugins/pushes/harmony/config")
-
-describe VagrantPlugins::HarmonyPush::Config do
- include_context "unit"
-
- let(:machine) { double("machine") }
-
- # For testing merging
- let(:one) { described_class.new }
- let(:two) { described_class.new }
-
- def assert_invalid
- errors = subject.validate(machine)
- if !errors.values.any? { |v| !v.empty? }
- raise "No errors: #{errors.inspect}"
- end
- end
-
- def assert_valid
- errors = subject.validate(machine)
- if !errors.values.all? { |v| v.empty? }
- raise "Errors: #{errors.inspect}"
- end
- end
-
- def valid_defaults
- end
-
- describe "defaults" do
- before { subject.finalize! }
-
- its(:app) { should be_nil }
- its(:dir) { should eq(".") }
- its(:exclude) { should be_empty }
- its(:include) { should be_empty }
- its(:uploader_path) { should be_nil }
- its(:vcs) { should be_true }
- end
-
- describe "app" do
- before do
- valid_defaults
- end
-
- it "is invalid if not set" do
- subject.app = ""
- subject.finalize!
- assert_invalid
- end
-
- it "is invalid if blank" do
- subject.app = " "
- subject.finalize!
- assert_invalid
- end
-
- it "is valid if set" do
- subject.app = "foo/bar"
- subject.finalize!
- assert_valid
- end
- end
-
- describe "exclude" do
- context "merge" do
- subject { one.merge(two) }
-
- it "appends" do
- one.exclude = ["foo"]
- two.exclude = ["bar"]
-
- expect(subject.exclude).to eq(["foo", "bar"])
- end
- end
- end
-
- describe "include" do
- context "merge" do
- subject { one.merge(two) }
-
- it "appends" do
- one.include = ["foo"]
- two.include = ["bar"]
-
- expect(subject.include).to eq(["foo", "bar"])
- end
- end
- end
-end
From dc8b36b31dde5a60d1634c1286badb17975b70b4 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 12 Nov 2014 17:11:11 -0500
Subject: [PATCH 058/203] Allow = methods for include and exclude
---
plugins/pushes/ftp/config.rb | 2 ++
1 file changed, 2 insertions(+)
diff --git a/plugins/pushes/ftp/config.rb b/plugins/pushes/ftp/config.rb
index 7ee1961a4..e493259db 100644
--- a/plugins/pushes/ftp/config.rb
+++ b/plugins/pushes/ftp/config.rb
@@ -109,12 +109,14 @@ module VagrantPlugins
def include(filepath)
@includes << filepath
end
+ alias_method :include=, :include
# Add the filepath to the list of excludes
# @param [String] filepath
def exclude(filepath)
@excludes << filepath
end
+ alias_method :exclude=, :exclude
private
From 8d090f2faa79ef637cb8ed5a39180db6eb1d8b4a Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 12 Nov 2014 17:11:41 -0500
Subject: [PATCH 059/203] Fix bad error message
---
templates/locales/en.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index 37ed84f07..a201a3833 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -950,8 +950,8 @@ en:
The Vagrantfile does not define any 'push' strategies. In order to use
`vagrant push`, you must define at least one push strategy:
- config.push :ftp do |strategy|
- # ... strategy-specific options
+ config.push.define "ftp" do |push|
+ # ... push-specific options
end
push_strategy_not_defined: |-
The push strategy '%{name}' is not defined in the Vagrantfile. Defined
From 1d7f4f26be995a5d003e8ee1fa43c00d67f5acb6 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 12 Nov 2014 17:11:57 -0500
Subject: [PATCH 060/203] Provide a better error message for the FTP push
---
plugins/pushes/ftp/locales/en.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/plugins/pushes/ftp/locales/en.yml b/plugins/pushes/ftp/locales/en.yml
index dcac3a427..0bbbe51f1 100644
--- a/plugins/pushes/ftp/locales/en.yml
+++ b/plugins/pushes/ftp/locales/en.yml
@@ -6,4 +6,6 @@ en:
requires you set this attribute. Please set this attribute in your
Vagrantfile, for example:
- push.%{attribute} = "..."
+ config.push.define "ftp" do |push|
+ push.%{attribute} = "..."
+ end
From 7dd5b16218dc460daadaba0db33b742666ed3744 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 12 Nov 2014 17:12:13 -0500
Subject: [PATCH 061/203] Add preliminary website for pushes
---
website/docs/source/layouts/layout.erb | 9 ++++
website/docs/source/v2/push/atlas.html.md | 56 ++++++++++++++++++++
website/docs/source/v2/push/ftp.html.md | 62 +++++++++++++++++++++++
website/docs/source/v2/push/index.html.md | 59 +++++++++++++++++++++
4 files changed, 186 insertions(+)
create mode 100644 website/docs/source/v2/push/atlas.html.md
create mode 100644 website/docs/source/v2/push/ftp.html.md
create mode 100644 website/docs/source/v2/push/index.html.md
diff --git a/website/docs/source/layouts/layout.erb b/website/docs/source/layouts/layout.erb
index 688b7507d..0631ad128 100644
--- a/website/docs/source/layouts/layout.erb
+++ b/website/docs/source/layouts/layout.erb
@@ -288,6 +288,15 @@
<% end %>
+ >Push
+
+ <% if sidebar_section == "push" %>
+
+ <% end %>
+
>Other
<% if sidebar_section == "other" %>
diff --git a/website/docs/source/v2/push/atlas.html.md b/website/docs/source/v2/push/atlas.html.md
new file mode 100644
index 000000000..0d6347345
--- /dev/null
+++ b/website/docs/source/v2/push/atlas.html.md
@@ -0,0 +1,56 @@
+---
+page_title: "Vagrant Push - Atlas Strategy"
+sidebar_current: "push-atlas"
+description: |-
+ Atlas is HashiCorp's commercial offering to bring your Vagrant development
+ environments to production. The Vagrant Push Atlas strategy pushes your
+ application's code to HashiCorp's Atlas service.
+---
+
+# Vagrant Push
+
+## Atlas Strategy
+
+[Atlas][] is HashiCorp's commercial offering to bring your Vagrant development
+environments to production. You can read more about HashiCorp's Atlas and all
+its features on [the Atlas homepage][Atlas]. The Vagrant Push Atlas strategy
+pushes your application's code to HashiCorp's Atlas service.
+
+The Vagrant Push Atlas strategy supports the following configuration options:
+
+- `app` - The name of the application in [HashiCorp's Atlas][Atlas]. If the
+ application does not exist, it will be created with user confirmation.
+
+- `exclude` - Add a file or file pattern to exclude from the upload, relative to
+ the `dir`. This value may be specified multiple times and is additive.
+ `exclude` take precedence over `include` values.
+
+- `include` - Add a file or file pattern to include in the upload, relative to
+ the `dir`. This value may be specified multiple times and is additive.
+
+- `dir` - The base directory containing the files to upload. By default this is
+ the same directory as the Vagrantfile, but you can specify this if you have
+ a `src` folder or `bin` folder or some other folder you want to upload.
+
+- `vsc` - If set to true, Vagrant will automatically use VCS data to determine
+ the files to upload. Uncommitted changes will not be deployed.
+
+
+### Usage
+
+The Vagrant Push Atlas strategy is defined in the `Vagrantfile` using the
+`atlas` key:
+
+```ruby
+config.push.define "atlas" do |push|
+ push.app = "username/application"
+end
+```
+
+And then push the application to Atlas:
+
+```shell
+$ vagrant push
+```
+
+[Atlas]: https://atlas.hashicorp.com/ "HashiCorp's Atlas Service"
diff --git a/website/docs/source/v2/push/ftp.html.md b/website/docs/source/v2/push/ftp.html.md
new file mode 100644
index 000000000..54a2e1427
--- /dev/null
+++ b/website/docs/source/v2/push/ftp.html.md
@@ -0,0 +1,62 @@
+---
+page_title: "Vagrant Push - FTP & SFTP Strategy"
+sidebar_current: "push-ftp"
+description: |-
+
+---
+
+# Vagrant Push
+
+## FTP & SFTP Strategy
+
+Vagrant Push FTP and SFTP strategy pushes the code in your Vagrant development
+environment to a remote FTP or SFTP server.
+
+The Vagrant Push FTP And SFTP strategy supports the following configuration
+options:
+
+- `host` - The address of the remote (S)FTP server. If the (S)FTP server is
+ running on a non-standard port, you can specify the port after the address
+ (`host:port`).
+
+- `username` - The username to use for authentication with the (S)FTP server.
+
+- `password` - The password to use for authentication with the (S)FTP server.
+
+- `passive` - Use passive FTP (default is true).
+
+- `secure` - Use secure (SFTP) (default is false).
+
+- `destination` - The root destination on the target system to sync the files
+ (default is `/`).
+
+- `exclude` - Add a file or file pattern to exclude from the upload, relative to
+ the `dir`. This value may be specified multiple times and is additive.
+ `exclude` take precedence over `include` values.
+
+- `include` - Add a file or file pattern to include in the upload, relative to
+ the `dir`. This value may be specified multiple times and is additive.
+
+- `dir` - The base directory containing the files to upload. By default this is
+ the same directory as the Vagrantfile, but you can specify this if you have
+ a `src` folder or `bin` folder or some other folder you want to upload.
+
+
+### Usage
+
+The Vagrant Push FTP and SFTP strategy is defined in the `Vagrantfile` using the
+`ftp` key:
+
+```ruby
+config.push.define "ftp" do |push|
+ push.host = "ftp.company.com"
+ push.username = "username"
+ push.password = "password"
+end
+```
+
+And then push the application to the FTP or SFTP server:
+
+```shell
+$ vagrant push
+```
diff --git a/website/docs/source/v2/push/index.html.md b/website/docs/source/v2/push/index.html.md
new file mode 100644
index 000000000..224787ca6
--- /dev/null
+++ b/website/docs/source/v2/push/index.html.md
@@ -0,0 +1,59 @@
+---
+page_title: "Vagrant Push"
+sidebar_current: "push"
+description: |-
+ Vagrant Push is a revolutionary
+---
+
+# Vagrant Push
+
+As of version 1.8, Vagrant is capable of deploying or "pushing" application code
+running as part of the Vagrant VM to a remote such as an FTP server or
+[HashiCorp's Atlas][Atlas].
+
+Pushes are defined in an application's `Vagrantfile` and are invoked using the
+`vagrant push` subcommand. Much like other components of Vagrant, each Vagrant
+Push plugin has its own configuration options. Please consult the documentation
+for your Vagrant Push plugin for more information. Here is an example Vagrant
+Push configuration section in a `Vagrantfile`:
+
+```ruby
+config.push.define "ftp" do |push|
+ push.host = "ftp.company.com"
+ push.username = "..."
+ # ...
+end
+```
+
+When the application is ready to be deployed to the FTP server, just run a
+single command:
+
+```shell
+$ vagrant push
+```
+
+Much like [Vagrant Providers][], Vagrant Push also supports multiple backend
+declarations. Consider the common scenario of a staging and QA environment:
+
+```ruby
+config.push.define "staging", strategy: "ftp" do |push|
+ # ...
+end
+
+config.push.define "qa", strategy: "ftp" do |push|
+ # ...
+end
+```
+
+In this scenario, the user must pass the name of the Vagrant Push to the
+subcommand:
+
+```shell
+$ vagrant push staging
+```
+
+Vagrant Push is the easiest way to deploy your application. You can read more
+in the documentation links on the sidebar.
+
+[Atlas]: https://atlas.hashicorp.com/ "HashiCorp's Atlas Service"
+[Vagrant Providers]: /v2/providers/index.html "Vagrant Providers"
From fb055637621aa7218732cfb2137b6e2ab993c901 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 12 Nov 2014 17:14:58 -0500
Subject: [PATCH 062/203] Load the translations in Atlas
---
plugins/pushes/atlas/plugin.rb | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/plugins/pushes/atlas/plugin.rb b/plugins/pushes/atlas/plugin.rb
index b5c213a80..2eee2517d 100644
--- a/plugins/pushes/atlas/plugin.rb
+++ b/plugins/pushes/atlas/plugin.rb
@@ -26,8 +26,7 @@ module VagrantPlugins
def self.init!
return if defined?(@_init)
- I18n.load_path << File.expand_path(
- "templates/locales/TODO.yml", Vagrant.source_root)
+ I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
I18n.reload!
@_init = true
end
From e38cf3152ca3d8562ce3a2915f8fd14a24436850 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 12 Nov 2014 17:26:52 -0500
Subject: [PATCH 063/203] Clarify what gets pushed
---
website/docs/source/v2/push/index.html.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/website/docs/source/v2/push/index.html.md b/website/docs/source/v2/push/index.html.md
index 224787ca6..310039176 100644
--- a/website/docs/source/v2/push/index.html.md
+++ b/website/docs/source/v2/push/index.html.md
@@ -8,7 +8,7 @@ description: |-
# Vagrant Push
As of version 1.8, Vagrant is capable of deploying or "pushing" application code
-running as part of the Vagrant VM to a remote such as an FTP server or
+in the same directory as your Vagrantfile to a remote such as an FTP server or
[HashiCorp's Atlas][Atlas].
Pushes are defined in an application's `Vagrantfile` and are invoked using the
From ad15be2e1690e191d7ec9e46a0669bdc17acb40f Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 13 Nov 2014 17:07:23 -0500
Subject: [PATCH 064/203] Fix a typo in ftp config test
---
test/unit/plugins/pushes/ftp/config_test.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/unit/plugins/pushes/ftp/config_test.rb b/test/unit/plugins/pushes/ftp/config_test.rb
index ef5010395..f66eeb791 100644
--- a/test/unit/plugins/pushes/ftp/config_test.rb
+++ b/test/unit/plugins/pushes/ftp/config_test.rb
@@ -57,7 +57,7 @@ describe VagrantPlugins::FTPPush::Config do
end
describe "#dir" do
- it "defaults to nil" do
+ it "defaults to ." do
subject.finalize!
expect(subject.dir).to eq(".")
end
From d4058130e401fd50af0d0c88d022a9ab60d73387 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 13 Nov 2014 17:07:41 -0500
Subject: [PATCH 065/203] Add heroku config
---
plugins/pushes/heroku/config.rb | 86 +++++++++++++
plugins/pushes/heroku/locales/en.yml | 30 +++++
.../unit/plugins/pushes/heroku/config_test.rb | 117 ++++++++++++++++++
3 files changed, 233 insertions(+)
create mode 100644 plugins/pushes/heroku/config.rb
create mode 100644 plugins/pushes/heroku/locales/en.yml
create mode 100644 test/unit/plugins/pushes/heroku/config_test.rb
diff --git a/plugins/pushes/heroku/config.rb b/plugins/pushes/heroku/config.rb
new file mode 100644
index 000000000..fd7b210ce
--- /dev/null
+++ b/plugins/pushes/heroku/config.rb
@@ -0,0 +1,86 @@
+module VagrantPlugins
+ module HerokuPush
+ class Config < Vagrant.plugin("2", :config)
+ # The name of the Heroku application to push to.
+ # @return [String]
+ attr_accessor :app
+
+ # The base directory with file contents to upload. By default this
+ # is the same directory as the Vagrantfile, but you can specify this
+ # if you have a `src` folder or `bin` folder or some other folder
+ # you want to upload. This directory must be a git repository.
+ # @return [String]
+ attr_accessor :dir
+
+ # The path to the git binary to shell out to. This usually is only set for
+ # debugging/development. If not set, the git bin will be searched for
+ # in the PATH.
+ # @return [String]
+ attr_accessor :git_bin
+
+ # The Git remote to push to (default: "heroku").
+ # @return [String]
+ attr_accessor :remote
+
+ # The Git branch to push to (default: "master").
+ # @return [String]
+ attr_accessor :branch
+
+ def initialize
+ @app = UNSET_VALUE
+ @dir = UNSET_VALUE
+
+ @git_bin = UNSET_VALUE
+ @remote = UNSET_VALUE
+ @branch = UNSET_VALUE
+ end
+
+ def finalize!
+ @app = nil if @app == UNSET_VALUE
+ @dir = "." if @dir == UNSET_VALUE
+
+ @git_bin = "git" if @git_bin == UNSET_VALUE
+ @remote = "heroku" if @remote == UNSET_VALUE
+ @branch = "master" if @branch == UNSET_VALUE
+ end
+
+ def validate(machine)
+ errors = _detected_errors
+
+ if missing?(@dir)
+ errors << I18n.t("heroku_push.errors.missing_attribute",
+ attribute: "dir",
+ )
+ end
+
+ if missing?(@git_bin)
+ errors << I18n.t("heroku_push.errors.missing_attribute",
+ attribute: "git_bin",
+ )
+ end
+
+ if missing?(@remote)
+ errors << I18n.t("heroku_push.errors.missing_attribute",
+ attribute: "remote",
+ )
+ end
+
+ if missing?(@branch)
+ errors << I18n.t("heroku_push.errors.missing_attribute",
+ attribute: "branch",
+ )
+ end
+
+ { "Heroku push" => errors }
+ end
+
+ private
+
+ # Determine if the given string is "missing" (blank)
+ # @return [true, false]
+ def missing?(obj)
+ obj.to_s.strip.empty?
+ end
+ end
+ end
+end
diff --git a/plugins/pushes/heroku/locales/en.yml b/plugins/pushes/heroku/locales/en.yml
new file mode 100644
index 000000000..e6f6bf441
--- /dev/null
+++ b/plugins/pushes/heroku/locales/en.yml
@@ -0,0 +1,30 @@
+en:
+ heroku_push:
+ errors:
+ command_failed: |-
+ The following command exited with a non-zero exit status:
+
+ %{cmd}
+
+ stdout: %{stdout}
+ stderr: %{stderr}
+ git_not_found: |-
+ The Git binary '%{bin}' could not be found. Please ensure you
+ have downloaded and installed the latest version of Git:
+
+ http://git-scm.com/downloads
+ missing_attribute: |-
+ Missing required attribute '%{attribute}'. The Vagrant Heroku Push
+ plugin requires you set this attribute. Please set this attribute in
+ your Vagrantfile, for example:
+
+ config.push.define "heroku" do |push|
+ push.%{attribute} = "..."
+ end
+ not_a_git_repo: |-
+ The following path is not a valid Git repository:
+
+ %{path}
+
+ Please ensure you are working in the correct directory. In order to use
+ the Vagrant Heroku Push plugin, you must have a git repository.
diff --git a/test/unit/plugins/pushes/heroku/config_test.rb b/test/unit/plugins/pushes/heroku/config_test.rb
new file mode 100644
index 000000000..0a157b17e
--- /dev/null
+++ b/test/unit/plugins/pushes/heroku/config_test.rb
@@ -0,0 +1,117 @@
+require_relative "../../../base"
+
+require Vagrant.source_root.join("plugins/pushes/heroku/config")
+
+describe VagrantPlugins::HerokuPush::Config do
+ include_context "unit"
+
+ before(:all) do
+ I18n.load_path << Vagrant.source_root.join("plugins/pushes/heroku/locales/en.yml")
+ I18n.reload!
+ end
+
+ subject { described_class.new }
+
+ let(:machine) { double("machine") }
+
+ describe "#app" do
+ it "defaults to nil" do
+ subject.finalize!
+ expect(subject.app).to be(nil)
+ end
+ end
+
+ describe "#dir" do
+ it "defaults to ." do
+ subject.finalize!
+ expect(subject.dir).to eq(".")
+ end
+ end
+
+ describe "#git_bin" do
+ it "defaults to git" do
+ subject.finalize!
+ expect(subject.git_bin).to eq("git")
+ end
+ end
+
+ describe "#remote" do
+ it "defaults to git" do
+ subject.finalize!
+ expect(subject.remote).to eq("heroku")
+ end
+ end
+
+ describe "#branch" do
+ it "defaults to git" do
+ subject.finalize!
+ expect(subject.branch).to eq("master")
+ end
+ end
+
+ describe "#validate" do
+ before do
+ allow(machine).to receive(:env)
+ .and_return(double("env",
+ root_path: "",
+ ))
+
+ subject.app = "bacon"
+ subject.dir = "."
+ subject.git_bin = "git"
+ subject.remote = "heroku"
+ subject.branch = "master"
+ end
+
+ let(:result) { subject.validate(machine) }
+ let(:errors) { result["Heroku push"] }
+
+ context "when the app is missing" do
+ it "does not return an error" do
+ subject.app = ""
+ subject.finalize!
+ expect(errors).to be_empty
+ end
+ end
+
+ context "when the git_bin is missing" do
+ it "returns an error" do
+ subject.git_bin = ""
+ subject.finalize!
+ expect(errors).to include(I18n.t("heroku_push.errors.missing_attribute",
+ attribute: "git_bin",
+ ))
+ end
+ end
+
+ context "when the remote is missing" do
+ it "returns an error" do
+ subject.remote = ""
+ subject.finalize!
+ expect(errors).to include(I18n.t("heroku_push.errors.missing_attribute",
+ attribute: "remote",
+ ))
+ end
+ end
+
+ context "when the branch is missing" do
+ it "returns an error" do
+ subject.branch = ""
+ subject.finalize!
+ expect(errors).to include(I18n.t("heroku_push.errors.missing_attribute",
+ attribute: "branch",
+ ))
+ end
+ end
+
+ context "when the dir is missing" do
+ it "returns an error" do
+ subject.dir = ""
+ subject.finalize!
+ expect(errors).to include(I18n.t("heroku_push.errors.missing_attribute",
+ attribute: "dir",
+ ))
+ end
+ end
+ end
+end
From c16dc5c9c9b2baaf11b8cc48f59763516ca150a8 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 13 Nov 2014 17:07:54 -0500
Subject: [PATCH 066/203] Add heroku push implementation
---
plugins/pushes/heroku/errors.rb | 21 ++
plugins/pushes/heroku/push.rb | 110 ++++++++
test/unit/plugins/pushes/heroku/push_test.rb | 279 +++++++++++++++++++
3 files changed, 410 insertions(+)
create mode 100644 plugins/pushes/heroku/errors.rb
create mode 100644 plugins/pushes/heroku/push.rb
create mode 100644 test/unit/plugins/pushes/heroku/push_test.rb
diff --git a/plugins/pushes/heroku/errors.rb b/plugins/pushes/heroku/errors.rb
new file mode 100644
index 000000000..c92a7b76c
--- /dev/null
+++ b/plugins/pushes/heroku/errors.rb
@@ -0,0 +1,21 @@
+module VagrantPlugins
+ module HerokuPush
+ module Errors
+ class Error < Vagrant::Errors::VagrantError
+ error_namespace("heroku_push.errors")
+ end
+
+ class CommandFailed < Error
+ error_key(:command_failed)
+ end
+
+ class GitNotFound < Error
+ error_key(:git_not_found)
+ end
+
+ class NotAGitRepo < Error
+ error_key(:not_a_git_repo)
+ end
+ end
+ end
+end
diff --git a/plugins/pushes/heroku/push.rb b/plugins/pushes/heroku/push.rb
new file mode 100644
index 000000000..8f50c4580
--- /dev/null
+++ b/plugins/pushes/heroku/push.rb
@@ -0,0 +1,110 @@
+require "vagrant/util/safe_exec"
+require "vagrant/util/subprocess"
+require "vagrant/util/which"
+
+require_relative "errors"
+
+module VagrantPlugins
+ module HerokuPush
+ class Push < Vagrant.plugin("2", :push)
+ def push
+ # Expand any paths relative to the root
+ dir = File.expand_path(config.dir, env.root_path)
+
+ # Verify git is installed
+ verify_git_bin!(config.git_bin)
+
+ # Verify we are operating in a git repo
+ verify_git_repo!(dir)
+
+ # Check if we need to add the git remote
+ if !has_git_remote?(config.remote, dir)
+ add_heroku_git_remote(config.remote, config.app, dir)
+ end
+
+ # Push to Heroku
+ git_push_heroku(config.remote, config.branch, dir)
+ end
+
+ # Verify that git is installed.
+ # @raise [Errors::GitNotFound]
+ def verify_git_bin!(path)
+ if Vagrant::Util::Which.which(path).nil?
+ raise Errors::GitNotFound, bin: path
+ end
+ end
+
+ # Verify that the given path is a git directory.
+ # @raise [Errors::NotAGitRepo]
+ # @param [String]
+ def verify_git_repo!(path)
+ if !File.directory?(git_dir(path))
+ raise Errors::NotAGitRepo, path: path
+ end
+ end
+
+ # The git directory for the given path.
+ # @param [String] path
+ # @return [String]
+ def git_dir(path)
+ "#{path}/.git"
+ end
+
+ # Push to the Heroku remote.
+ # @param [String] remote
+ # @param [String] branch
+ def git_push_heroku(remote, branch, path)
+ execute!("git",
+ "--git-dir", git_dir(path),
+ "--work-tree", path,
+ "push", remote, branch,
+ )
+ end
+
+ # Check if the git remote has the given remote.
+ # @param [String] remote
+ # @return [true, false]
+ def has_git_remote?(remote, path)
+ result = execute!("git",
+ "--git-dir", git_dir(path),
+ "--work-tree", path,
+ "remote",
+ )
+ remotes = result.stdout.split(/\r?\n/).map(&:strip)
+ remotes.include?(remote.to_s)
+ end
+
+ # Add the Heroku to the current repository.
+ # @param [String] remote
+ # @param [String] app
+ def add_heroku_git_remote(remote, app, path)
+ execute!("git",
+ "--git-dir", git_dir(path),
+ "--work-tree", path,
+ "remote", "add", remote, heroku_git_url(app),
+ )
+ end
+
+ # The URL for this project on Heroku.
+ # @return [String]
+ def heroku_git_url(app)
+ "git@heroku.com:#{app}.git"
+ end
+
+ # Execute the command, raising an exception if it fails.
+ # @return [Vagrant::Util::Subprocess::Result]
+ def execute!(*cmd)
+ result = Vagrant::Util::Subprocess.execute(*cmd)
+
+ if result.exit_code != 0
+ raise Errors::CommandFailed,
+ cmd: cmd.join(" "),
+ stdout: result.stdout,
+ stderr: result.stderr
+ end
+
+ result
+ end
+ end
+ end
+end
diff --git a/test/unit/plugins/pushes/heroku/push_test.rb b/test/unit/plugins/pushes/heroku/push_test.rb
new file mode 100644
index 000000000..1bec15927
--- /dev/null
+++ b/test/unit/plugins/pushes/heroku/push_test.rb
@@ -0,0 +1,279 @@
+require_relative "../../../base"
+
+require Vagrant.source_root.join("plugins/pushes/heroku/push")
+
+describe VagrantPlugins::HerokuPush::Push do
+ include_context "unit"
+
+ before(:all) do
+ I18n.load_path << Vagrant.source_root.join("plugins/pushes/heroku/locales/en.yml")
+ I18n.reload!
+ end
+
+ let(:env) { isolated_environment }
+ let(:config) do
+ double("config",
+ app: "bacon",
+ dir: "lib",
+ git_bin: "git",
+ remote: "heroku",
+ branch: "master",
+ )
+ end
+
+ subject { described_class.new(env, config) }
+
+ describe "#push" do
+ let(:root_path) { "/handy/dandy" }
+ let(:dir) { "#{root_path}/#{config.dir}" }
+
+ before do
+ allow(subject).to receive(:verify_git_bin!)
+ allow(subject).to receive(:verify_git_repo!)
+ allow(subject).to receive(:has_git_remote?)
+ allow(subject).to receive(:add_heroku_git_remote)
+ allow(subject).to receive(:git_push_heroku)
+ allow(subject).to receive(:execute!)
+
+ allow(env).to receive(:root_path)
+ .and_return(root_path)
+ end
+
+ it "verifies the git bin is present" do
+ expect(subject).to receive(:verify_git_bin!)
+ .with(config.git_bin)
+ subject.push
+ end
+
+ it "verifies the directory is a git repo" do
+ expect(subject).to receive(:verify_git_repo!)
+ .with(dir)
+ subject.push
+ end
+
+ context "when the heroku remote exists" do
+ before do
+ allow(subject).to receive(:has_git_remote?)
+ .and_return(true)
+ end
+
+ it "does not add the heroku remote" do
+ expect(subject).to_not receive(:add_heroku_git_remote)
+ subject.push
+ end
+ end
+
+ context "when the heroku remote does not exist" do
+ before do
+ allow(subject).to receive(:has_git_remote?)
+ .and_return(false)
+ end
+
+ it "adds the heroku remote" do
+ expect(subject).to receive(:add_heroku_git_remote)
+ .with(config.remote, config.app, dir)
+ subject.push
+ end
+ end
+
+ it "pushes to heroku" do
+ expect(subject).to receive(:git_push_heroku)
+ .with(config.remote, config.branch, dir)
+ subject.push
+ end
+ end
+
+ describe "#verify_git_bin!" do
+ context "when git does not exist" do
+ before do
+ allow(Vagrant::Util::Which).to receive(:which)
+ .with("git")
+ .and_return(nil)
+ end
+
+ it "raises an exception" do
+ expect {
+ subject.verify_git_bin!("git")
+ } .to raise_error(VagrantPlugins::HerokuPush::Errors::GitNotFound) { |error|
+ expect(error.message).to eq(I18n.t("heroku_push.errors.git_not_found",
+ bin: "git",
+ ))
+ }
+ end
+ end
+
+ context "when git exists" do
+ before do
+ allow(Vagrant::Util::Which).to receive(:which)
+ .with("git")
+ .and_return("git")
+ end
+
+ it "does not raise an exception" do
+ expect { subject.verify_git_bin!("git") }.to_not raise_error
+ end
+ end
+ end
+
+ describe "#verify_git_repo!" do
+ context "when the path is a git repo" do
+ before do
+ allow(File).to receive(:directory?)
+ .with("/repo/path/.git")
+ .and_return(false)
+ end
+
+ it "raises an exception" do
+ expect {
+ subject.verify_git_repo!("/repo/path")
+ } .to raise_error(VagrantPlugins::HerokuPush::Errors::NotAGitRepo) { |error|
+ expect(error.message).to eq(I18n.t("heroku_push.errors.not_a_git_repo",
+ path: "/repo/path",
+ ))
+ }
+ end
+ end
+
+ context "when the path is not a git repo" do
+ before do
+ allow(File).to receive(:directory?)
+ .with("/repo/path/.git")
+ .and_return(true)
+ end
+
+ it "does not raise an exception" do
+ expect { subject.verify_git_repo!("/repo/path") }.to_not raise_error
+ end
+ end
+ end
+
+ describe "#git_push_heroku" do
+ let(:dir) { "." }
+
+ before { allow(subject).to receive(:execute!) }
+
+ it "executes the proper command" do
+ expect(subject).to receive(:execute!)
+ .with("git",
+ "--git-dir", "#{dir}/.git",
+ "--work-tree", dir,
+ "push", "bacon", "hamlet",
+ )
+ subject.git_push_heroku("bacon", "hamlet", dir)
+ end
+ end
+
+ describe "#has_git_remote?" do
+ let(:dir) { "." }
+
+ let(:process) do
+ double("process",
+ stdout: "origin\r\nbacon\nhello"
+ )
+ end
+
+ before do
+ allow(subject).to receive(:execute!)
+ .and_return(process)
+ end
+
+ it "executes the proper command" do
+ expect(subject).to receive(:execute!)
+ .with("git",
+ "--git-dir", "#{dir}/.git",
+ "--work-tree", dir,
+ "remote",
+ )
+ subject.has_git_remote?("bacon", dir)
+ end
+
+ it "returns true when the remote exists" do
+ expect(subject.has_git_remote?("origin", dir)).to be(true)
+ expect(subject.has_git_remote?("bacon", dir)).to be(true)
+ expect(subject.has_git_remote?("hello", dir)).to be(true)
+ end
+
+ it "returns false when the remote does not exist" do
+ expect(subject.has_git_remote?("nope", dir)).to be(false)
+ end
+ end
+
+ describe "#add_heroku_git_remote" do
+ let(:dir) { "." }
+
+ before do
+ allow(subject).to receive(:execute!)
+ allow(subject).to receive(:heroku_git_url)
+ .with("app")
+ .and_return("HEROKU_URL")
+ end
+
+ it "executes the proper command" do
+ expect(subject).to receive(:execute!)
+ .with("git",
+ "--git-dir", "#{dir}/.git",
+ "--work-tree", dir,
+ "remote", "add", "bacon", "HEROKU_URL",
+ )
+ subject.add_heroku_git_remote("bacon", "app", dir)
+ end
+ end
+
+ describe "#heroku_git_url" do
+ it "returns the proper string" do
+ expect(subject.heroku_git_url("bacon"))
+ .to eq("git@heroku.com:bacon.git")
+ end
+ end
+
+ describe "#git_dir" do
+ it "returns the .git directory for the path" do
+ expect(subject.git_dir("/path")).to eq("/path/.git")
+ end
+ end
+
+ describe "#execute!" do
+ let(:exit_code) { 0 }
+ let(:stdout) { "This is the output" }
+ let(:stderr) { "This is the errput" }
+
+ let(:process) do
+ double("process",
+ exit_code: exit_code,
+ stdout: stdout,
+ stderr: stderr,
+ )
+ end
+
+ before do
+ allow(Vagrant::Util::Subprocess).to receive(:execute)
+ .and_return(process)
+ end
+
+ it "creates a subprocess" do
+ expect(Vagrant::Util::Subprocess).to receive(:execute)
+ expect { subject.execute! }.to_not raise_error
+ end
+
+ it "returns the resulting process" do
+ expect(subject.execute!).to be(process)
+ end
+
+ context "when the exit code is non-zero" do
+ let(:exit_code) { 1 }
+
+ it "raises an exception" do
+ klass = VagrantPlugins::HerokuPush::Errors::CommandFailed
+ cmd = ["foo", "bar"]
+
+ expect { subject.execute!(*cmd) }.to raise_error(klass) { |error|
+ expect(error.message).to eq(I18n.t("heroku_push.errors.command_failed",
+ cmd: cmd.join(" "),
+ stdout: stdout,
+ stderr: stderr,
+ ))
+ }
+ end
+ end
+ end
+end
From 4282fcf55e9159860c1b81f558e8f82c898c36a0 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 13 Nov 2014 17:08:34 -0500
Subject: [PATCH 067/203] Add heroku push plugin file
---
plugins/pushes/heroku/plugin.rb | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
create mode 100644 plugins/pushes/heroku/plugin.rb
diff --git a/plugins/pushes/heroku/plugin.rb b/plugins/pushes/heroku/plugin.rb
new file mode 100644
index 000000000..40865ee5d
--- /dev/null
+++ b/plugins/pushes/heroku/plugin.rb
@@ -0,0 +1,33 @@
+require "vagrant"
+
+module VagrantPlugins
+ module HerokuPush
+ class Plugin < Vagrant.plugin("2")
+ name "heroku"
+ description <<-DESC
+ Deploy to a Heroku
+ DESC
+
+ config(:heroku, :push) do
+ require File.expand_path("../config", __FILE__)
+ init!
+ Config
+ end
+
+ push(:heroku) do
+ require File.expand_path("../push", __FILE__)
+ init!
+ Push
+ end
+
+ protected
+
+ def self.init!
+ return if defined?(@_init)
+ I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
+ I18n.reload!
+ @_init = true
+ end
+ end
+ end
+end
From ce380a3b121d14817c1191ee040b9cf2147b2a00 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 13 Nov 2014 17:11:24 -0500
Subject: [PATCH 068/203] Remove safe_exec (not being used)
---
plugins/pushes/heroku/push.rb | 1 -
1 file changed, 1 deletion(-)
diff --git a/plugins/pushes/heroku/push.rb b/plugins/pushes/heroku/push.rb
index 8f50c4580..cab46de7a 100644
--- a/plugins/pushes/heroku/push.rb
+++ b/plugins/pushes/heroku/push.rb
@@ -1,4 +1,3 @@
-require "vagrant/util/safe_exec"
require "vagrant/util/subprocess"
require "vagrant/util/which"
From 1f49b7ef62c1771adc38d040f1cf235b5aa298a5 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 13 Nov 2014 17:46:54 -0500
Subject: [PATCH 069/203] Remove branch option (it should be interpreted)
---
plugins/pushes/heroku/config.rb | 12 ------------
test/unit/plugins/pushes/heroku/config_test.rb | 18 ------------------
2 files changed, 30 deletions(-)
diff --git a/plugins/pushes/heroku/config.rb b/plugins/pushes/heroku/config.rb
index fd7b210ce..927c1a7b9 100644
--- a/plugins/pushes/heroku/config.rb
+++ b/plugins/pushes/heroku/config.rb
@@ -22,17 +22,12 @@ module VagrantPlugins
# @return [String]
attr_accessor :remote
- # The Git branch to push to (default: "master").
- # @return [String]
- attr_accessor :branch
-
def initialize
@app = UNSET_VALUE
@dir = UNSET_VALUE
@git_bin = UNSET_VALUE
@remote = UNSET_VALUE
- @branch = UNSET_VALUE
end
def finalize!
@@ -41,7 +36,6 @@ module VagrantPlugins
@git_bin = "git" if @git_bin == UNSET_VALUE
@remote = "heroku" if @remote == UNSET_VALUE
- @branch = "master" if @branch == UNSET_VALUE
end
def validate(machine)
@@ -65,12 +59,6 @@ module VagrantPlugins
)
end
- if missing?(@branch)
- errors << I18n.t("heroku_push.errors.missing_attribute",
- attribute: "branch",
- )
- end
-
{ "Heroku push" => errors }
end
diff --git a/test/unit/plugins/pushes/heroku/config_test.rb b/test/unit/plugins/pushes/heroku/config_test.rb
index 0a157b17e..e451ad152 100644
--- a/test/unit/plugins/pushes/heroku/config_test.rb
+++ b/test/unit/plugins/pushes/heroku/config_test.rb
@@ -42,13 +42,6 @@ describe VagrantPlugins::HerokuPush::Config do
end
end
- describe "#branch" do
- it "defaults to git" do
- subject.finalize!
- expect(subject.branch).to eq("master")
- end
- end
-
describe "#validate" do
before do
allow(machine).to receive(:env)
@@ -60,7 +53,6 @@ describe VagrantPlugins::HerokuPush::Config do
subject.dir = "."
subject.git_bin = "git"
subject.remote = "heroku"
- subject.branch = "master"
end
let(:result) { subject.validate(machine) }
@@ -94,16 +86,6 @@ describe VagrantPlugins::HerokuPush::Config do
end
end
- context "when the branch is missing" do
- it "returns an error" do
- subject.branch = ""
- subject.finalize!
- expect(errors).to include(I18n.t("heroku_push.errors.missing_attribute",
- attribute: "branch",
- ))
- end
- end
-
context "when the dir is missing" do
it "returns an error" do
subject.dir = ""
From b9e8f6e892db97ac09a0cbaa1bdbb5862729e98f Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 13 Nov 2014 17:47:08 -0500
Subject: [PATCH 070/203] Interpret the current branch to push to Heroku
---
plugins/pushes/heroku/push.rb | 21 ++++++++-
test/unit/plugins/pushes/heroku/push_test.rb | 45 ++++++++++++++++++--
2 files changed, 61 insertions(+), 5 deletions(-)
diff --git a/plugins/pushes/heroku/push.rb b/plugins/pushes/heroku/push.rb
index cab46de7a..17dc75a04 100644
--- a/plugins/pushes/heroku/push.rb
+++ b/plugins/pushes/heroku/push.rb
@@ -10,6 +10,9 @@ module VagrantPlugins
# Expand any paths relative to the root
dir = File.expand_path(config.dir, env.root_path)
+ # Get the current branch
+ branch = git_branch(dir)
+
# Verify git is installed
verify_git_bin!(config.git_bin)
@@ -22,7 +25,7 @@ module VagrantPlugins
end
# Push to Heroku
- git_push_heroku(config.remote, config.branch, dir)
+ git_push_heroku(config.remote, branch, dir)
end
# Verify that git is installed.
@@ -49,6 +52,20 @@ module VagrantPlugins
"#{path}/.git"
end
+ # The name of the current git branch.
+ # @param [String] path
+ # @return [String]
+ def git_branch(path)
+ result = execute!("git",
+ "--git-dir", git_dir(path),
+ "--work-tree", path,
+ "branch",
+ )
+
+ # Returns something like "* master"
+ result.stdout.sub("*", "").strip
+ end
+
# Push to the Heroku remote.
# @param [String] remote
# @param [String] branch
@@ -56,7 +73,7 @@ module VagrantPlugins
execute!("git",
"--git-dir", git_dir(path),
"--work-tree", path,
- "push", remote, branch,
+ "push", remote, "#{branch}:master",
)
end
diff --git a/test/unit/plugins/pushes/heroku/push_test.rb b/test/unit/plugins/pushes/heroku/push_test.rb
index 1bec15927..ab5a64eee 100644
--- a/test/unit/plugins/pushes/heroku/push_test.rb
+++ b/test/unit/plugins/pushes/heroku/push_test.rb
@@ -17,17 +17,20 @@ describe VagrantPlugins::HerokuPush::Push do
dir: "lib",
git_bin: "git",
remote: "heroku",
- branch: "master",
)
end
subject { described_class.new(env, config) }
describe "#push" do
+ let(:branch) { "master" }
+
let(:root_path) { "/handy/dandy" }
let(:dir) { "#{root_path}/#{config.dir}" }
before do
+ allow(subject).to receive(:git_branch)
+ .and_return(branch)
allow(subject).to receive(:verify_git_bin!)
allow(subject).to receive(:verify_git_repo!)
allow(subject).to receive(:has_git_remote?)
@@ -78,7 +81,7 @@ describe VagrantPlugins::HerokuPush::Push do
it "pushes to heroku" do
expect(subject).to receive(:git_push_heroku)
- .with(config.remote, config.branch, dir)
+ .with(config.remote, branch, dir)
subject.push
end
end
@@ -157,7 +160,7 @@ describe VagrantPlugins::HerokuPush::Push do
.with("git",
"--git-dir", "#{dir}/.git",
"--work-tree", dir,
- "push", "bacon", "hamlet",
+ "push", "bacon", "hamlet:master",
)
subject.git_push_heroku("bacon", "hamlet", dir)
end
@@ -232,6 +235,42 @@ describe VagrantPlugins::HerokuPush::Push do
end
end
+ describe "#git_branch" do
+ let(:stdout) { "" }
+ let(:process) { double("process", stdout: stdout) }
+
+ before do
+ allow(subject).to receive(:execute!)
+ .and_return(process)
+ end
+
+ let(:branch) { subject.git_branch("/path") }
+
+ context "when the branch is prefixed with a star" do
+ let(:stdout) { "*bacon" }
+
+ it "returns the correct name" do
+ expect(branch).to eq("bacon")
+ end
+ end
+
+ context "when the branch is prefixed with a star space" do
+ let(:stdout) { "* bacon" }
+
+ it "returns the correct name" do
+ expect(branch).to eq("bacon")
+ end
+ end
+
+ context "when the branch is not prefixed" do
+ let(:stdout) { "bacon" }
+
+ it "returns the correct name" do
+ expect(branch).to eq("bacon")
+ end
+ end
+ end
+
describe "#execute!" do
let(:exit_code) { 0 }
let(:stdout) { "This is the output" }
From ea512a95f3d4b19fc12d72b5e283e681d2439c0e Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 13 Nov 2014 17:47:16 -0500
Subject: [PATCH 071/203] Add Heroku push docs
---
website/docs/source/layouts/layout.erb | 1 +
website/docs/source/v2/push/heroku.html.md | 63 ++++++++++++++++++++++
2 files changed, 64 insertions(+)
create mode 100644 website/docs/source/v2/push/heroku.html.md
diff --git a/website/docs/source/layouts/layout.erb b/website/docs/source/layouts/layout.erb
index 0631ad128..315408de5 100644
--- a/website/docs/source/layouts/layout.erb
+++ b/website/docs/source/layouts/layout.erb
@@ -294,6 +294,7 @@
<% end %>
diff --git a/website/docs/source/v2/push/heroku.html.md b/website/docs/source/v2/push/heroku.html.md
new file mode 100644
index 000000000..dc730dc62
--- /dev/null
+++ b/website/docs/source/v2/push/heroku.html.md
@@ -0,0 +1,63 @@
+---
+page_title: "Vagrant Push - Heroku Strategy"
+sidebar_current: "push-heroku"
+description: |-
+ The Vagrant Push Heroku strategy pushes your application's code to Heroku.
+ Only files which are committed to the Git repository are pushed to Heroku.
+---
+
+# Vagrant Push
+
+## Heroku Strategy
+
+[Heroku][] is a public IAAS provider that makes it easy to deploy an
+application. The Vagrant Push Heroku strategy pushes your application's code to
+Heroku.
+
+
+
+ Warning: The Vagrant Push Heroku strategy requires you
+ have configured your Heroku credentials and created the Heroku application.
+ This documentation will not cover these prerequisites, but you can read more
+ about them in the Heroku documentation.
+
+
+
+Only files which are committed to the Git repository will be pushed to Heroku.
+Additionally, the current working branch is always pushed to the Heroku, even if
+it is not the "master" branch.
+
+The Vagrant Push Heroku strategy supports the following configuration options:
+
+- `app` - The name of the Heroku application. If the Heroku application does not
+ exist, an exception will be raised. If this value is not specified, the
+ basename of the directory containing the `Vagrantfile` is assumed to be the
+ name of the Heroku application. Since this value can change between users, it
+ is highly recommended that you add the `app` setting to your `Vagrantfile`.
+
+- `dir` - The base directory containing the Git repository to upload to Heroku.
+ By default this is the same directory as the Vagrantfile, but you can specify
+ this if you have a nested Git directory.
+
+- `remote` - The name of the Git remote where Heroku is configured. The default
+ value is "heroku".
+
+
+### Usage
+
+The Vagrant Push Heroku strategy is defined in the `Vagrantfile` using the
+`heroku` key:
+
+```ruby
+config.push.define "heroku" do |push|
+ push.app = "my_application"
+end
+```
+
+And then push the application to Heroku:
+
+```shell
+$ vagrant push
+```
+
+[Heroku]: https://heroku.com/ "Heroku"
From 7e3de3951e6d403887c646919392785c21267858 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 13 Nov 2014 18:00:30 -0500
Subject: [PATCH 072/203] Do not check for a branch until after we have found
git
---
plugins/pushes/heroku/push.rb | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/pushes/heroku/push.rb b/plugins/pushes/heroku/push.rb
index 17dc75a04..360db9af0 100644
--- a/plugins/pushes/heroku/push.rb
+++ b/plugins/pushes/heroku/push.rb
@@ -10,15 +10,15 @@ module VagrantPlugins
# Expand any paths relative to the root
dir = File.expand_path(config.dir, env.root_path)
- # Get the current branch
- branch = git_branch(dir)
-
# Verify git is installed
verify_git_bin!(config.git_bin)
# Verify we are operating in a git repo
verify_git_repo!(dir)
+ # Get the current branch
+ branch = git_branch(dir)
+
# Check if we need to add the git remote
if !has_git_remote?(config.remote, dir)
add_heroku_git_remote(config.remote, config.app, dir)
From 9d1a43c7668f38f845421fd66fe1a46246d3dd42 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 13 Nov 2014 18:00:43 -0500
Subject: [PATCH 073/203] Interpret the app from the CWD
---
plugins/pushes/heroku/push.rb | 12 +++++++++++-
test/unit/plugins/pushes/heroku/push_test.rb | 6 ++++++
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/plugins/pushes/heroku/push.rb b/plugins/pushes/heroku/push.rb
index 360db9af0..b894eba81 100644
--- a/plugins/pushes/heroku/push.rb
+++ b/plugins/pushes/heroku/push.rb
@@ -19,9 +19,12 @@ module VagrantPlugins
# Get the current branch
branch = git_branch(dir)
+ # Get the name of the app
+ app = config.app || interpret_app(dir)
+
# Check if we need to add the git remote
if !has_git_remote?(config.remote, dir)
- add_heroku_git_remote(config.remote, config.app, dir)
+ add_heroku_git_remote(config.remote, app, dir)
end
# Push to Heroku
@@ -45,6 +48,13 @@ module VagrantPlugins
end
end
+ # Interpret the name of the Heroku application from the given path.
+ # @param [String] path
+ # @return [String]
+ def interpret_app(path)
+ File.basename(path)
+ end
+
# The git directory for the given path.
# @param [String] path
# @return [String]
diff --git a/test/unit/plugins/pushes/heroku/push_test.rb b/test/unit/plugins/pushes/heroku/push_test.rb
index ab5a64eee..c0337e41f 100644
--- a/test/unit/plugins/pushes/heroku/push_test.rb
+++ b/test/unit/plugins/pushes/heroku/push_test.rb
@@ -222,6 +222,12 @@ describe VagrantPlugins::HerokuPush::Push do
end
end
+ describe "#interpret_app" do
+ it "returns the basename of the directory" do
+ expect(subject.interpret_app("/foo/bar/blitz")).to eq("blitz")
+ end
+ end
+
describe "#heroku_git_url" do
it "returns the proper string" do
expect(subject.heroku_git_url("bacon"))
From 612eeb22654ebecacc6e367773cef7603afd8eec Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 14 Nov 2014 15:51:35 -0500
Subject: [PATCH 074/203] Add local-exec push
---
plugins/pushes/local-exec/config.rb | 37 +++++++++
plugins/pushes/local-exec/errors.rb | 13 ++++
plugins/pushes/local-exec/locales/en.yml | 18 +++++
plugins/pushes/local-exec/plugin.rb | 33 ++++++++
plugins/pushes/local-exec/push.rb | 28 +++++++
.../plugins/pushes/local-exec/config_test.rb | 45 +++++++++++
.../plugins/pushes/local-exec/push_test.rb | 78 +++++++++++++++++++
7 files changed, 252 insertions(+)
create mode 100644 plugins/pushes/local-exec/config.rb
create mode 100644 plugins/pushes/local-exec/errors.rb
create mode 100644 plugins/pushes/local-exec/locales/en.yml
create mode 100644 plugins/pushes/local-exec/plugin.rb
create mode 100644 plugins/pushes/local-exec/push.rb
create mode 100644 test/unit/plugins/pushes/local-exec/config_test.rb
create mode 100644 test/unit/plugins/pushes/local-exec/push_test.rb
diff --git a/plugins/pushes/local-exec/config.rb b/plugins/pushes/local-exec/config.rb
new file mode 100644
index 000000000..eb06a72fe
--- /dev/null
+++ b/plugins/pushes/local-exec/config.rb
@@ -0,0 +1,37 @@
+module VagrantPlugins
+ module LocalExecPush
+ class Config < Vagrant.plugin("2", :config)
+ # The command (as a string) to execute.
+ # @return [String]
+ attr_accessor :command
+
+ def initialize
+ @command = UNSET_VALUE
+ end
+
+ def finalize!
+ @command = nil if @command == UNSET_VALUE
+ end
+
+ def validate(machine)
+ errors = _detected_errors
+
+ if missing?(@command)
+ errors << I18n.t("local_exec_push.errors.missing_attribute",
+ attribute: "command",
+ )
+ end
+
+ { "Local Exec push" => errors }
+ end
+
+ private
+
+ # Determine if the given string is "missing" (blank)
+ # @return [true, false]
+ def missing?(obj)
+ obj.to_s.strip.empty?
+ end
+ end
+ end
+end
diff --git a/plugins/pushes/local-exec/errors.rb b/plugins/pushes/local-exec/errors.rb
new file mode 100644
index 000000000..5e5b71cca
--- /dev/null
+++ b/plugins/pushes/local-exec/errors.rb
@@ -0,0 +1,13 @@
+module VagrantPlugins
+ module LocalExecPush
+ module Errors
+ class Error < Vagrant::Errors::VagrantError
+ error_namespace("local_exec_push.errors")
+ end
+
+ class CommandFailed < Error
+ error_key(:command_failed)
+ end
+ end
+ end
+end
diff --git a/plugins/pushes/local-exec/locales/en.yml b/plugins/pushes/local-exec/locales/en.yml
new file mode 100644
index 000000000..bd219c8ff
--- /dev/null
+++ b/plugins/pushes/local-exec/locales/en.yml
@@ -0,0 +1,18 @@
+en:
+ local_exec_push:
+ errors:
+ command_failed: |-
+ The following command exited with a non-zero exit status:
+
+ %{cmd}
+
+ stdout: %{stdout}
+ stderr: %{stderr}
+ missing_attribute: |-
+ Missing required attribute '%{attribute}'. The Vagrant Local Exec Push
+ plugin requires you set this attribute. Please set this attribute in
+ your Vagrantfile, for example:
+
+ config.push.define "local-exec" do |push|
+ push.%{attribute} = "..."
+ end
diff --git a/plugins/pushes/local-exec/plugin.rb b/plugins/pushes/local-exec/plugin.rb
new file mode 100644
index 000000000..9f8be467b
--- /dev/null
+++ b/plugins/pushes/local-exec/plugin.rb
@@ -0,0 +1,33 @@
+require "vagrant"
+
+module VagrantPlugins
+ module LocalExecPush
+ class Plugin < Vagrant.plugin("2")
+ name "local-exec"
+ description <<-DESC
+ Run a local command or script to push
+ DESC
+
+ config(:local_exec, :push) do
+ require File.expand_path("../config", __FILE__)
+ init!
+ Config
+ end
+
+ push(:local_exec) do
+ require File.expand_path("../push", __FILE__)
+ init!
+ Push
+ end
+
+ protected
+
+ def self.init!
+ return if defined?(@_init)
+ I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
+ I18n.reload!
+ @_init = true
+ end
+ end
+ end
+end
diff --git a/plugins/pushes/local-exec/push.rb b/plugins/pushes/local-exec/push.rb
new file mode 100644
index 000000000..cbcab39e7
--- /dev/null
+++ b/plugins/pushes/local-exec/push.rb
@@ -0,0 +1,28 @@
+require "vagrant/util/subprocess"
+
+require_relative "errors"
+
+module VagrantPlugins
+ module LocalExecPush
+ class Push < Vagrant.plugin("2", :push)
+ def push
+ execute!(config.command)
+ end
+
+ # Execute the command, raising an exception if it fails.
+ # @return [Vagrant::Util::Subprocess::Result]
+ def execute!(*cmd)
+ result = Vagrant::Util::Subprocess.execute(*cmd)
+
+ if result.exit_code != 0
+ raise Errors::CommandFailed,
+ cmd: cmd.join(" "),
+ stdout: result.stdout,
+ stderr: result.stderr
+ end
+
+ result
+ end
+ end
+ end
+end
diff --git a/test/unit/plugins/pushes/local-exec/config_test.rb b/test/unit/plugins/pushes/local-exec/config_test.rb
new file mode 100644
index 000000000..84cc9d7b4
--- /dev/null
+++ b/test/unit/plugins/pushes/local-exec/config_test.rb
@@ -0,0 +1,45 @@
+require_relative "../../../base"
+
+require Vagrant.source_root.join("plugins/pushes/local-exec/config")
+
+describe VagrantPlugins::LocalExecPush::Config do
+ include_context "unit"
+
+ before(:all) do
+ I18n.load_path << Vagrant.source_root.join("plugins/pushes/local-exec/locales/en.yml")
+ I18n.reload!
+ end
+
+ let(:machine) { double("machine") }
+
+ describe "#command" do
+ it "defaults to nil" do
+ subject.finalize!
+ expect(subject.command).to be(nil)
+ end
+ end
+
+ describe "#validate" do
+ before do
+ allow(machine).to receive(:env)
+ .and_return(double("env",
+ root_path: "",
+ ))
+
+ subject.command = "echo"
+ end
+
+ let(:result) { subject.validate(machine) }
+ let(:errors) { result["Local Exec push"] }
+
+ context "when the command is missing" do
+ it "returns an error" do
+ subject.command = ""
+ subject.finalize!
+ expect(errors).to include(I18n.t("local_exec_push.errors.missing_attribute",
+ attribute: "command",
+ ))
+ end
+ end
+ end
+end
diff --git a/test/unit/plugins/pushes/local-exec/push_test.rb b/test/unit/plugins/pushes/local-exec/push_test.rb
new file mode 100644
index 000000000..23f487546
--- /dev/null
+++ b/test/unit/plugins/pushes/local-exec/push_test.rb
@@ -0,0 +1,78 @@
+require_relative "../../../base"
+
+require Vagrant.source_root.join("plugins/pushes/local-exec/push")
+
+describe VagrantPlugins::LocalExecPush::Push do
+ include_context "unit"
+
+ before(:all) do
+ I18n.load_path << Vagrant.source_root.join("plugins/pushes/local-exec/locales/en.yml")
+ I18n.reload!
+ end
+
+ let(:env) { isolated_environment }
+ let(:config) do
+ double("config",
+ command: "echo",
+ )
+ end
+
+ subject { described_class.new(env, config) }
+
+ describe "#push" do
+ before do
+ allow(subject).to receive(:execute!)
+ end
+
+ it "executes the command" do
+ expect(subject).to receive(:execute!)
+ .with(config.command)
+ subject.push
+ end
+ end
+
+ describe "#execute!" do
+ let(:exit_code) { 0 }
+ let(:stdout) { "This is the output" }
+ let(:stderr) { "This is the errput" }
+
+ let(:process) do
+ double("process",
+ exit_code: exit_code,
+ stdout: stdout,
+ stderr: stderr,
+ )
+ end
+
+ before do
+ allow(Vagrant::Util::Subprocess).to receive(:execute)
+ .and_return(process)
+ end
+
+ it "creates a subprocess" do
+ expect(Vagrant::Util::Subprocess).to receive(:execute)
+ expect { subject.execute! }.to_not raise_error
+ end
+
+ it "returns the resulting process" do
+ expect(subject.execute!).to be(process)
+ end
+
+ context "when the exit code is non-zero" do
+ let(:exit_code) { 1 }
+
+ it "raises an exception" do
+ klass = VagrantPlugins::LocalExecPush::Errors::CommandFailed
+ cmd = ["foo", "bar"]
+
+ expect { subject.execute!(*cmd) }.to raise_error(klass) { |error|
+ expect(error.message).to eq(I18n.t("local_exec_push.errors.command_failed",
+ cmd: cmd.join(" "),
+ stdout: stdout,
+ stderr: stderr,
+ ))
+ }
+ end
+ end
+ end
+end
From 24595cb606f73380ad69be1b0a5496ab4a5bc614 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 14 Nov 2014 15:51:40 -0500
Subject: [PATCH 075/203] Add docs for local-exec
---
website/docs/source/layouts/layout.erb | 5 +-
.../docs/source/v2/push/local-exec.html.md | 46 +++++++++++++++++++
2 files changed, 49 insertions(+), 2 deletions(-)
create mode 100644 website/docs/source/v2/push/local-exec.html.md
diff --git a/website/docs/source/layouts/layout.erb b/website/docs/source/layouts/layout.erb
index 315408de5..8a1883920 100644
--- a/website/docs/source/layouts/layout.erb
+++ b/website/docs/source/layouts/layout.erb
@@ -293,8 +293,9 @@
<% if sidebar_section == "push" %>
<% end %>
diff --git a/website/docs/source/v2/push/local-exec.html.md b/website/docs/source/v2/push/local-exec.html.md
new file mode 100644
index 000000000..4c6c64d47
--- /dev/null
+++ b/website/docs/source/v2/push/local-exec.html.md
@@ -0,0 +1,46 @@
+---
+page_title: "Vagrant Push - Local Exec Strategy"
+sidebar_current: "push-local-exec"
+description: |-
+ The Vagrant Push Heroku strategy pushes your application's code to Heroku.
+ Only files which are committed to the Git repository are pushed to Heroku.
+---
+
+# Vagrant Push
+
+## Local Exec Strategy
+
+The Vagrant Push Local Exec strategy allows the user to invoke an arbitrary
+shell command or script as part of a push.
+
+
+
+ Warning: The Vagrant Push Local Exec strategy does not
+ perform any validation on the correctness of the shell script.
+
+
+
+The Vagrant Push Local Exec strategy supports the following configuration
+options:
+
+- `command` - The command to execute (as a string).
+
+
+### Usage
+
+The Vagrant Push Local Exec strategy is defined in the `Vagrantfile` using the
+`local-exec` key:
+
+```ruby
+config.push.define "local-exec" do |push|
+ push.command = <<-SCRIPT
+ scp . /var/www/website
+ SCRIPT
+end
+```
+
+And then invoke the push with Vagrant:
+
+```shell
+$ vagrant push
+```
From fb53f6f3f2bd47eaee8cf96f3b7b650436b01691 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 14 Nov 2014 15:53:47 -0500
Subject: [PATCH 076/203] Fix description for local-exec docs
---
website/docs/source/v2/push/local-exec.html.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/website/docs/source/v2/push/local-exec.html.md b/website/docs/source/v2/push/local-exec.html.md
index 4c6c64d47..b5eb0d487 100644
--- a/website/docs/source/v2/push/local-exec.html.md
+++ b/website/docs/source/v2/push/local-exec.html.md
@@ -2,8 +2,8 @@
page_title: "Vagrant Push - Local Exec Strategy"
sidebar_current: "push-local-exec"
description: |-
- The Vagrant Push Heroku strategy pushes your application's code to Heroku.
- Only files which are committed to the Git repository are pushed to Heroku.
+ The Vagrant Push Local Exec strategy pushes your application's code using a
+ user-defined script.
---
# Vagrant Push
From aa60fe60318cc13a828b0894fe697b3879f77f97 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Fri, 14 Nov 2014 15:55:14 -0500
Subject: [PATCH 077/203] Add example of reading the file
---
website/docs/source/v2/push/local-exec.html.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/website/docs/source/v2/push/local-exec.html.md b/website/docs/source/v2/push/local-exec.html.md
index b5eb0d487..4e3727f85 100644
--- a/website/docs/source/v2/push/local-exec.html.md
+++ b/website/docs/source/v2/push/local-exec.html.md
@@ -39,6 +39,15 @@ config.push.define "local-exec" do |push|
end
```
+For more complicated scripts, you may store them in a separate file and read
+them from the `Vagrantfile` like so:
+
+```ruby
+config.push.define "local-exec" do |push|
+ push.command = File.read("my-script.sh")
+end
+```
+
And then invoke the push with Vagrant:
```shell
From ede14d7daa03afa59833c37461e903186a81d04a Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Mon, 17 Nov 2014 13:16:39 -0500
Subject: [PATCH 078/203] Separate local-exec push `script` from `inline`
---
plugins/pushes/local-exec/config.rb | 21 ++++--
plugins/pushes/local-exec/locales/en.yml | 4 ++
plugins/pushes/local-exec/push.rb | 32 ++++++++-
.../plugins/pushes/local-exec/config_test.rb | 62 ++++++++++++++---
.../plugins/pushes/local-exec/push_test.rb | 69 +++++++++++++++++--
5 files changed, 165 insertions(+), 23 deletions(-)
diff --git a/plugins/pushes/local-exec/config.rb b/plugins/pushes/local-exec/config.rb
index eb06a72fe..747ff8925 100644
--- a/plugins/pushes/local-exec/config.rb
+++ b/plugins/pushes/local-exec/config.rb
@@ -1,27 +1,38 @@
module VagrantPlugins
module LocalExecPush
class Config < Vagrant.plugin("2", :config)
+ # The path (relative to the machine root) to a local script that will be
+ # executed.
+ # @return [String]
+ attr_accessor :script
+
# The command (as a string) to execute.
# @return [String]
- attr_accessor :command
+ attr_accessor :inline
def initialize
- @command = UNSET_VALUE
+ @script = UNSET_VALUE
+ @inline = UNSET_VALUE
end
def finalize!
- @command = nil if @command == UNSET_VALUE
+ @script = nil if @script == UNSET_VALUE
+ @inline = nil if @inline == UNSET_VALUE
end
def validate(machine)
errors = _detected_errors
- if missing?(@command)
+ if missing?(@script) && missing?(@inline)
errors << I18n.t("local_exec_push.errors.missing_attribute",
- attribute: "command",
+ attribute: "script",
)
end
+ if !missing?(@script) && !missing?(@inline)
+ errors << I18n.t("local_exec_push.errors.cannot_specify_script_and_inline")
+ end
+
{ "Local Exec push" => errors }
end
diff --git a/plugins/pushes/local-exec/locales/en.yml b/plugins/pushes/local-exec/locales/en.yml
index bd219c8ff..08808a879 100644
--- a/plugins/pushes/local-exec/locales/en.yml
+++ b/plugins/pushes/local-exec/locales/en.yml
@@ -1,6 +1,10 @@
en:
local_exec_push:
errors:
+ cannot_specify_script_and_inline: |-
+ You have specified both the 'script' and 'inline' attributes for the
+ Vagrant Local Exec Push plugin. You may only specify one of these
+ attributes.
command_failed: |-
The following command exited with a non-zero exit status:
diff --git a/plugins/pushes/local-exec/push.rb b/plugins/pushes/local-exec/push.rb
index cbcab39e7..be74e68d5 100644
--- a/plugins/pushes/local-exec/push.rb
+++ b/plugins/pushes/local-exec/push.rb
@@ -1,3 +1,5 @@
+require "fileutils"
+require "tempfile"
require "vagrant/util/subprocess"
require_relative "errors"
@@ -6,11 +8,35 @@ module VagrantPlugins
module LocalExecPush
class Push < Vagrant.plugin("2", :push)
def push
- execute!(config.command)
+ if config.inline
+ execute_inline!(config.inline)
+ else
+ execute_script!(config.script)
+ end
end
- # Execute the command, raising an exception if it fails.
- # @return [Vagrant::Util::Subprocess::Result]
+ # Execute the inline script by writing it to a tempfile and executing.
+ def execute_inline!(inline)
+ script = Tempfile.new(["vagrant-local-exec-script", ".sh"])
+ script.write(inline)
+ script.rewind
+
+ execute_script!(script.path)
+ ensure
+ if script
+ script.close
+ script.unlink
+ end
+ end
+
+ # Execute the script, expanding the path relative to the current env root.
+ def execute_script!(path)
+ path = File.expand_path(path, env.root_path)
+ FileUtils.chmod("+x", path)
+ execute!(path)
+ end
+
+ # Execute the script, raising an exception if it fails.
def execute!(*cmd)
result = Vagrant::Util::Subprocess.execute(*cmd)
diff --git a/test/unit/plugins/pushes/local-exec/config_test.rb b/test/unit/plugins/pushes/local-exec/config_test.rb
index 84cc9d7b4..045872d2f 100644
--- a/test/unit/plugins/pushes/local-exec/config_test.rb
+++ b/test/unit/plugins/pushes/local-exec/config_test.rb
@@ -12,10 +12,17 @@ describe VagrantPlugins::LocalExecPush::Config do
let(:machine) { double("machine") }
- describe "#command" do
+ describe "#script" do
it "defaults to nil" do
subject.finalize!
- expect(subject.command).to be(nil)
+ expect(subject.script).to be(nil)
+ end
+ end
+
+ describe "#inline" do
+ it "defaults to nil" do
+ subject.finalize!
+ expect(subject.inline).to be(nil)
end
end
@@ -25,20 +32,53 @@ describe VagrantPlugins::LocalExecPush::Config do
.and_return(double("env",
root_path: "",
))
-
- subject.command = "echo"
+ subject.finalize!
end
let(:result) { subject.validate(machine) }
let(:errors) { result["Local Exec push"] }
- context "when the command is missing" do
- it "returns an error" do
- subject.command = ""
- subject.finalize!
- expect(errors).to include(I18n.t("local_exec_push.errors.missing_attribute",
- attribute: "command",
- ))
+ context "when script is present" do
+ before { subject.script = "foo.sh" }
+
+ context "when inline is present" do
+ before { subject.inline = "echo" }
+
+ it "returns an error" do
+ expect(errors).to include(
+ I18n.t("local_exec_push.errors.cannot_specify_script_and_inline")
+ )
+ end
+ end
+
+ context "when inline is not present" do
+ before { subject.inline = "" }
+
+ it "does not return an error" do
+ expect(errors).to be_empty
+ end
+ end
+ end
+
+ context "when script is not present" do
+ before { subject.script = "" }
+
+ context "when inline is present" do
+ before { subject.inline = "echo" }
+
+ it "does not return an error" do
+ expect(errors).to be_empty
+ end
+ end
+
+ context "when inline is not present" do
+ before { subject.inline = "" }
+
+ it "returns an error" do
+ expect(errors).to include(I18n.t("local_exec_push.errors.missing_attribute",
+ attribute: "script",
+ ))
+ end
end
end
end
diff --git a/test/unit/plugins/pushes/local-exec/push_test.rb b/test/unit/plugins/pushes/local-exec/push_test.rb
index 23f487546..6896428d1 100644
--- a/test/unit/plugins/pushes/local-exec/push_test.rb
+++ b/test/unit/plugins/pushes/local-exec/push_test.rb
@@ -13,21 +13,82 @@ describe VagrantPlugins::LocalExecPush::Push do
let(:env) { isolated_environment }
let(:config) do
double("config",
- command: "echo",
+ script: nil,
+ inline: nil,
)
end
subject { described_class.new(env, config) }
+ before do
+ allow(env).to receive(:root_path)
+ .and_return(File.expand_path("..", __FILE__))
+ end
+
describe "#push" do
before do
+ allow(subject).to receive(:execute_inline!)
+ allow(subject).to receive(:execute_script!)
allow(subject).to receive(:execute!)
end
- it "executes the command" do
+ context "when inline is given" do
+ before { allow(config).to receive(:inline).and_return("echo") }
+
+ it "executes the inline script" do
+ expect(subject).to receive(:execute_inline!)
+ .with(config.inline)
+ subject.push
+ end
+ end
+
+ context "when script is given" do
+ before { allow(config).to receive(:script).and_return("foo.sh") }
+
+ it "executes the script" do
+ expect(subject).to receive(:execute_script!)
+ .with(config.script)
+ subject.push
+ end
+ end
+ end
+
+ describe "#execute_inline!" do
+ before { allow(subject).to receive(:execute_script!) }
+
+ it "writes the script to a tempfile" do
+ expect(Tempfile).to receive(:new).and_call_original
+ subject.execute_inline!("echo")
+ end
+
+ it "executes the script" do
+ expect(subject).to receive(:execute_script!)
+ subject.execute_inline!("echo")
+ end
+ end
+
+ describe "#execute_script!" do
+ before do
+ allow(subject).to receive(:execute!)
+ allow(FileUtils).to receive(:chmod)
+ end
+
+ it "expands the path relative to the machine root" do
expect(subject).to receive(:execute!)
- .with(config.command)
- subject.push
+ .with(File.expand_path("foo.sh", env.root_path))
+ subject.execute_script!("./foo.sh")
+ end
+
+ it "makes the file executable" do
+ expect(FileUtils).to receive(:chmod)
+ .with("+x", File.expand_path("foo.sh", env.root_path))
+ subject.execute_script!("./foo.sh")
+ end
+
+ it "calls execute!" do
+ expect(subject).to receive(:execute!)
+ .with(File.expand_path("foo.sh", env.root_path))
+ subject.execute_script!("./foo.sh")
end
end
From 202326875f866cfe3df7e9a0769638e1c8f64e8e Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Mon, 17 Nov 2014 13:22:40 -0500
Subject: [PATCH 079/203] Update docs for local-exec push
---
website/docs/source/v2/push/local-exec.html.md | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/website/docs/source/v2/push/local-exec.html.md b/website/docs/source/v2/push/local-exec.html.md
index 4e3727f85..536a5eab9 100644
--- a/website/docs/source/v2/push/local-exec.html.md
+++ b/website/docs/source/v2/push/local-exec.html.md
@@ -23,8 +23,13 @@ shell command or script as part of a push.
The Vagrant Push Local Exec strategy supports the following configuration
options:
-- `command` - The command to execute (as a string).
+- `script` - The path to a script on disk (relative to the `Vagrantfile`) to
+ execute. Vagrant will attempt to convert this script to an executable, but an
+ exception will be raised if that fails.
+- `inline` - The inline script to execute (as a string).
+Please note - only one of the `script` and `inline` options may be specified in
+a single push definition.
### Usage
@@ -33,7 +38,7 @@ The Vagrant Push Local Exec strategy is defined in the `Vagrantfile` using the
```ruby
config.push.define "local-exec" do |push|
- push.command = <<-SCRIPT
+ push.inline = <<-SCRIPT
scp . /var/www/website
SCRIPT
end
@@ -44,7 +49,7 @@ them from the `Vagrantfile` like so:
```ruby
config.push.define "local-exec" do |push|
- push.command = File.read("my-script.sh")
+ push.script = "my-script.sh"
end
```
From 998c5688e8a5bab24bfac078b2a28a264941533e Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Mon, 1 Dec 2014 21:52:03 -0800
Subject: [PATCH 080/203] pushes/atlas: Look for the uploader bin in the
embedded dir
---
plugins/pushes/atlas/push.rb | 8 +++---
test/unit/plugins/pushes/atlas/push_test.rb | 28 +++++++++++++++++++++
2 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/plugins/pushes/atlas/push.rb b/plugins/pushes/atlas/push.rb
index 7dd64a358..0dc90f725 100644
--- a/plugins/pushes/atlas/push.rb
+++ b/plugins/pushes/atlas/push.rb
@@ -43,10 +43,12 @@ module VagrantPlugins
end
if Vagrant.in_installer?
- # TODO: look up uploader in embedded dir
- else
- return Vagrant::Util::Which.which(UPLOADER_BIN)
+ path = File.join(
+ Vagrant.installer_embedded_dir, "bin", UPLOADER_BIN)
+ return path if File.file?(path)
end
+
+ return Vagrant::Util::Which.which(UPLOADER_BIN)
end
end
end
diff --git a/test/unit/plugins/pushes/atlas/push_test.rb b/test/unit/plugins/pushes/atlas/push_test.rb
index 40bb9b8d1..2073e5789 100644
--- a/test/unit/plugins/pushes/atlas/push_test.rb
+++ b/test/unit/plugins/pushes/atlas/push_test.rb
@@ -6,6 +6,8 @@ require Vagrant.source_root.join("plugins/pushes/atlas/push")
describe VagrantPlugins::AtlasPush::Push do
include_context "unit"
+ let(:bin) { VagrantPlugins::AtlasPush::Push::UPLOADER_BIN }
+
let(:env) do
double("env",
root_path: File.expand_path("..", __FILE__)
@@ -99,6 +101,32 @@ describe VagrantPlugins::AtlasPush::Push do
expect(subject.uploader_path).to eq("bar")
end
+ it "should look up the uploader in the embedded dir if installer" do
+ dir = temporary_dir
+
+ allow(Vagrant).to receive(:in_installer?).and_return(true)
+ allow(Vagrant).to receive(:installer_embedded_dir).and_return(dir.to_s)
+
+ bin_path = dir.join("bin", bin)
+ bin_path.dirname.mkpath
+ bin_path.open("w+") { |f| f.write("hi") }
+
+ expect(subject.uploader_path).to eq(bin_path.to_s)
+ end
+
+ it "should look up the uploader in the PATH if not in the installer" do
+ dir = temporary_dir
+
+ allow(Vagrant).to receive(:in_installer?).and_return(true)
+ allow(Vagrant).to receive(:installer_embedded_dir).and_return(dir.to_s)
+
+ expect(Vagrant::Util::Which).to receive(:which).
+ with(described_class.const_get(:UPLOADER_BIN)).
+ and_return("bar")
+
+ expect(subject.uploader_path).to eq("bar")
+ end
+
it "should return nil if its not found anywhere" do
allow(Vagrant).to receive(:in_installer?).and_return(false)
allow(Vagrant::Util::Which).to receive(:which).and_return(nil)
From 44e6ec6df8cfcda17a964e5169450a19e74fd087 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Mon, 1 Dec 2014 22:05:13 -0800
Subject: [PATCH 081/203] pushes/atlas: support custom server address
---
plugins/pushes/atlas/config.rb | 8 ++++++++
plugins/pushes/atlas/push.rb | 1 +
test/unit/plugins/pushes/atlas/push_test.rb | 8 ++++++++
3 files changed, 17 insertions(+)
diff --git a/plugins/pushes/atlas/config.rb b/plugins/pushes/atlas/config.rb
index 71b40e299..9941da455 100644
--- a/plugins/pushes/atlas/config.rb
+++ b/plugins/pushes/atlas/config.rb
@@ -41,10 +41,17 @@ module VagrantPlugins
# @return [String]
attr_accessor :uploader_path
+ # The address of the Atlas server to upload to. By default this will
+ # be the public Atlas server.
+ #
+ # @return [String]
+ attr_accessor :address
+
def initialize
@app = UNSET_VALUE
@dir = UNSET_VALUE
@vcs = UNSET_VALUE
+ @address = UNSET_VALUE
@includes = []
@excludes = []
@uploader_path = UNSET_VALUE
@@ -58,6 +65,7 @@ module VagrantPlugins
end
def finalize!
+ @address = nil if @address == UNSET_VALUE
@app = nil if @app == UNSET_VALUE
@dir = "." if @dir == UNSET_VALUE
@uploader_path = nil if @uploader_path == UNSET_VALUE
diff --git a/plugins/pushes/atlas/push.rb b/plugins/pushes/atlas/push.rb
index 0dc90f725..0b13f1bb3 100644
--- a/plugins/pushes/atlas/push.rb
+++ b/plugins/pushes/atlas/push.rb
@@ -26,6 +26,7 @@ module VagrantPlugins
cmd << "-vcs" if config.vcs
cmd += config.includes.map { |v| ["-include", v] }
cmd += config.excludes.map { |v| ["-exclude", v] }
+ cmd += ["-address", config.address] if config.address
cmd << config.app
cmd << File.expand_path(config.dir, env.root_path)
Vagrant::Util::SafeExec.exec(uploader, *cmd.flatten)
diff --git a/test/unit/plugins/pushes/atlas/push_test.rb b/test/unit/plugins/pushes/atlas/push_test.rb
index 2073e5789..b93231bb1 100644
--- a/test/unit/plugins/pushes/atlas/push_test.rb
+++ b/test/unit/plugins/pushes/atlas/push_test.rb
@@ -83,6 +83,14 @@ describe VagrantPlugins::AtlasPush::Push do
config.excludes = ["foo", "bar"]
subject.execute("foo")
end
+
+ it "sends custom server address" do
+ expect(Vagrant::Util::SafeExec).to receive(:exec).
+ with("foo", "-vcs", "-address", "foo", app, env.root_path.to_s)
+
+ config.address = "foo"
+ subject.execute("foo")
+ end
end
describe "#uploader_path" do
From 4a64da5663796f5c2245da6835f6493082d8c039 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Mon, 1 Dec 2014 22:20:27 -0800
Subject: [PATCH 082/203] Fix some issues around push, fix tests, add missing
translations
---
plugins/commands/push/command.rb | 2 +-
plugins/pushes/atlas/errors.rb | 2 +-
plugins/pushes/atlas/locales/en.yml | 6 ++++++
test/unit/plugins/commands/push/command_test.rb | 6 +++---
4 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/plugins/commands/push/command.rb b/plugins/commands/push/command.rb
index dc02f7ba7..398e4e279 100644
--- a/plugins/commands/push/command.rb
+++ b/plugins/commands/push/command.rb
@@ -49,7 +49,7 @@ module VagrantPlugins
raise Vagrant::Errors::PushStrategyNotProvided, pushes: pushes
end
else
- if !pushes.key?(name.to_sym)
+ if !pushes.include?(name.to_sym)
raise Vagrant::Errors::PushStrategyNotDefined,
name: name,
pushes: pushes
diff --git a/plugins/pushes/atlas/errors.rb b/plugins/pushes/atlas/errors.rb
index 6fee42698..7ba1d712a 100644
--- a/plugins/pushes/atlas/errors.rb
+++ b/plugins/pushes/atlas/errors.rb
@@ -6,7 +6,7 @@ module VagrantPlugins
end
class UploaderNotFound < Error
- error_key(:uploader_error)
+ error_key(:uploader_not_found)
end
end
end
diff --git a/plugins/pushes/atlas/locales/en.yml b/plugins/pushes/atlas/locales/en.yml
index 745e33bd2..c54d59e67 100644
--- a/plugins/pushes/atlas/locales/en.yml
+++ b/plugins/pushes/atlas/locales/en.yml
@@ -9,3 +9,9 @@ en:
config.push.define "atlas" do |push|
push.%{attribute} = "..."
end
+ uploader_not_found: |-
+ Vagrant was unable to find the Atlas uploader CLI. If your Vagrantfile
+ specifies the path explicitly with "uploader_path", then make sure that
+ path is valid. Otherwise, make sure that you have a valid install of
+ Vagrant. If you installed Vagrant outside of the official installers,
+ the "atlas-upload" binary must exist on your PATH.
diff --git a/test/unit/plugins/commands/push/command_test.rb b/test/unit/plugins/commands/push/command_test.rb
index 85be81766..18998e87a 100644
--- a/test/unit/plugins/commands/push/command_test.rb
+++ b/test/unit/plugins/commands/push/command_test.rb
@@ -42,7 +42,7 @@ describe VagrantPlugins::CommandPush::Command do
describe "#validate_pushes!" do
context "when there are no pushes defined" do
- let(:pushes) { {} }
+ let(:pushes) { [] }
context "when a strategy is given" do
it "raises an exception" do
@@ -61,7 +61,7 @@ describe VagrantPlugins::CommandPush::Command do
context "when there is one push defined" do
let(:noop) { double("noop") }
- let(:pushes) { { noop: noop } }
+ let(:pushes) { [:noop] }
context "when a strategy is given" do
context "when that strategy is not defined" do
@@ -90,7 +90,7 @@ describe VagrantPlugins::CommandPush::Command do
context "when there are multiple pushes defined" do
let(:noop) { double("noop") }
let(:ftp) { double("ftp") }
- let(:pushes) { { noop: noop, ftp: ftp } }
+ let(:pushes) { [:noop, :ftp] }
context "when a strategy is given" do
context "when that strategy is not defined" do
From 35dbb8db7dc151c15f13380ce47bd9def565e9a6 Mon Sep 17 00:00:00 2001
From: Josh Frye
Date: Tue, 2 Dec 2014 12:10:12 -0500
Subject: [PATCH 083/203] Typo
---
website/docs/source/v2/push/atlas.html.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/website/docs/source/v2/push/atlas.html.md b/website/docs/source/v2/push/atlas.html.md
index 0d6347345..f001cfa51 100644
--- a/website/docs/source/v2/push/atlas.html.md
+++ b/website/docs/source/v2/push/atlas.html.md
@@ -32,7 +32,7 @@ The Vagrant Push Atlas strategy supports the following configuration options:
the same directory as the Vagrantfile, but you can specify this if you have
a `src` folder or `bin` folder or some other folder you want to upload.
-- `vsc` - If set to true, Vagrant will automatically use VCS data to determine
+- `vcs` - If set to true, Vagrant will automatically use VCS data to determine
the files to upload. Uncommitted changes will not be deployed.
From 6b48199346bd73d2c7d9a8b4f32b54fe00b1b045 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 2 Dec 2014 13:30:16 -0500
Subject: [PATCH 084/203] Infer push name when only one strategy is defined,
support multiple strategies
---
lib/vagrant/environment.rb | 2 +-
plugins/commands/push/command.rb | 59 +++++++++++-------
.../plugins/commands/push/command_test.rb | 61 +++++++++++++++----
website/docs/source/v2/push/index.html.md | 10 +++
4 files changed, 98 insertions(+), 34 deletions(-)
diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb
index 82cab0411..acda0c178 100644
--- a/lib/vagrant/environment.rb
+++ b/lib/vagrant/environment.rb
@@ -571,7 +571,7 @@ module Vagrant
#
# @return [Array]
def pushes
- vagrantfile.config.push.__compiled_pushes.keys
+ self.vagrantfile.config.push.__compiled_pushes.keys
end
# This returns a machine with the proper provider for this environment.
diff --git a/plugins/commands/push/command.rb b/plugins/commands/push/command.rb
index 398e4e279..f3390723b 100644
--- a/plugins/commands/push/command.rb
+++ b/plugins/commands/push/command.rb
@@ -7,56 +7,73 @@ module VagrantPlugins
"deploys code in this environment to a configured destination"
end
- # @todo support multiple strategies if requested by the community
def execute
+ options = { all: false }
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant push [strategy] [options]"
+ o.on("-a", "--all", "Run all defined push strategies") do
+ options[:all] = true
+ end
end
# Parse the options
argv = parse_options(opts)
return if !argv
- name = argv[0]
- pushes = @env.pushes
+ names = validate_pushes!(@env.pushes, argv, options)
- validate_pushes!(pushes, name)
-
- @logger.debug("'push' environment with strategy: `#{name}'")
- @env.push(name)
+ names.each do |name|
+ @logger.debug("'push' environment with strategy: `#{name}'")
+ @env.push(name)
+ end
0
end
- # Validate that the given list of pushes and strategy are valid.
+ # Validate that the given list of names corresponds to valid pushes.
#
- # @raise [PushesNotDefined] if there are no pushes defined for the
- # environment
- # @raise [PushStrategyNotDefined] if a strategy is given, but does not
- # correspond to one that exists in the environment
+ # @raise Vagrant::Errors::PushesNotDefined
+ # if there are no pushes defined
+ # @raise Vagrant::Errors::PushStrategyNotProvided
+ # if there are multiple push strategies defined and none were specified
+ # and `--all` was not given
+ # @raise Vagrant::Errors::PushStrategyNotDefined
+ # if any of the given push names do not correspond to a push strategy
#
- # @param [Registry] pushes The list of pushes as a {Registry}
- # @param [#to_sym, nil] name The name of the strategy
+ # @param [Array] pushes
+ # the list of pushes defined by the environment
+ # @param [Array] names
+ # the list of names provided by the user on the command line
+ # @param [Hash] options
+ # a list of options to pass to the validation
#
- # @return [true]
- def validate_pushes!(pushes, name=nil)
+ # @return [Array]
+ # the compiled list of pushes
+ #
+ def validate_pushes!(pushes, names = [], options = {})
if pushes.nil? || pushes.empty?
raise Vagrant::Errors::PushesNotDefined
end
- if name.nil?
- if pushes.length != 1
+ names = Array(names).flatten.compact.map(&:to_sym)
+
+ if names.empty? || options[:all]
+ if options[:all] || pushes.length == 1
+ return pushes.map(&:to_sym)
+ else
raise Vagrant::Errors::PushStrategyNotProvided, pushes: pushes
end
- else
- if !pushes.include?(name.to_sym)
+ end
+
+ names.each do |name|
+ if !pushes.include?(name)
raise Vagrant::Errors::PushStrategyNotDefined,
name: name,
pushes: pushes
end
end
- true
+ return names
end
end
end
diff --git a/test/unit/plugins/commands/push/command_test.rb b/test/unit/plugins/commands/push/command_test.rb
index 18998e87a..292e2ee0e 100644
--- a/test/unit/plugins/commands/push/command_test.rb
+++ b/test/unit/plugins/commands/push/command_test.rb
@@ -25,15 +25,35 @@ describe VagrantPlugins::CommandPush::Command do
describe "#execute" do
before do
allow(subject).to receive(:validate_pushes!)
+ .and_return([:noop])
allow(env).to receive(:pushes)
allow(env).to receive(:push)
end
it "validates the pushes" do
- expect(subject).to receive(:validate_pushes!).once
+ expect(subject).to receive(:validate_pushes!)
+ .with(nil, argv, kind_of(Hash))
+ .once
subject.execute
end
+ it "parses arguments" do
+ list = ["noop", "ftp"]
+ instance = described_class.new(list, env)
+ expect(instance).to receive(:validate_pushes!)
+ .with(nil, list, kind_of(Hash))
+ .and_return([])
+ instance.execute
+ end
+
+ it "parses options" do
+ instance = described_class.new(["--all"], env)
+ expect(instance).to receive(:validate_pushes!)
+ .with(nil, argv, all: true)
+ .and_return([])
+ instance.execute
+ end
+
it "delegates to Environment#push" do
expect(env).to receive(:push).once
subject.execute
@@ -72,17 +92,22 @@ describe VagrantPlugins::CommandPush::Command do
end
context "when that strategy is defined" do
- it "does not raise an exception" do
- expect { subject.validate_pushes!(pushes, :noop) }
- .to_not raise_error
+ it "returns that push" do
+ expect(subject.validate_pushes!(pushes, :noop)).to eq([:noop])
end
end
end
context "when no strategy is given" do
- it "does not raise an exception" do
- expect { subject.validate_pushes!(pushes) }
- .to_not raise_error
+ it "returns the push" do
+ expect(subject.validate_pushes!(pushes)).to eq([:noop])
+ end
+ end
+
+ context "when --all is given" do
+ it "returns the push" do
+ expect(subject.validate_pushes!(pushes, [], all: true))
+ .to eq([:noop])
end
end
end
@@ -101,21 +126,33 @@ describe VagrantPlugins::CommandPush::Command do
end
context "when that strategy is defined" do
- it "does not raise an exception" do
- expect { subject.validate_pushes!(pushes, :noop) }
- .to_not raise_error
- expect { subject.validate_pushes!(pushes, :ftp) }
- .to_not raise_error
+ it "returns the strategy" do
+ expect(subject.validate_pushes!(pushes, :noop)).to eq([:noop])
+ expect(subject.validate_pushes!(pushes, :ftp)).to eq([:ftp])
end
end
end
+ context "when multiple strategies are given" do
+ it "returns the pushes" do
+ expect(subject.validate_pushes!(pushes, [:noop, :ftp]))
+ .to eq([:noop, :ftp])
+ end
+ end
+
context "when no strategy is given" do
it "raises an exception" do
expect { subject.validate_pushes!(pushes) }
.to raise_error(Vagrant::Errors::PushStrategyNotProvided)
end
end
+
+ context "when --all is given" do
+ it "returns the pushes" do
+ expect(subject.validate_pushes!(pushes, [], all: true))
+ .to eq([:noop, :ftp])
+ end
+ end
end
end
end
diff --git a/website/docs/source/v2/push/index.html.md b/website/docs/source/v2/push/index.html.md
index 310039176..5f061862a 100644
--- a/website/docs/source/v2/push/index.html.md
+++ b/website/docs/source/v2/push/index.html.md
@@ -52,6 +52,16 @@ subcommand:
$ vagrant push staging
```
+Pushes will be run in the order you specify on the command line, **not the order
+they are specified in the `Vagrantfile`!**
+
+To execute all the Vagrant Push strategies, specify the `--all` flag with no
+other arguments:
+
+```shell
+$ vagrant push --all
+```
+
Vagrant Push is the easiest way to deploy your application. You can read more
in the documentation links on the sidebar.
From 70b61047c748e05b39aa838460d8f697edecdfae Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 2 Dec 2014 13:44:42 -0500
Subject: [PATCH 085/203] Do not support multiple strategies right now
---
plugins/commands/push/command.rb | 45 ++++++-----------
.../plugins/commands/push/command_test.rb | 50 ++-----------------
website/docs/source/v2/push/index.html.md | 10 ----
3 files changed, 21 insertions(+), 84 deletions(-)
diff --git a/plugins/commands/push/command.rb b/plugins/commands/push/command.rb
index f3390723b..5fde89175 100644
--- a/plugins/commands/push/command.rb
+++ b/plugins/commands/push/command.rb
@@ -8,24 +8,18 @@ module VagrantPlugins
end
def execute
- options = { all: false }
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant push [strategy] [options]"
- o.on("-a", "--all", "Run all defined push strategies") do
- options[:all] = true
- end
end
# Parse the options
argv = parse_options(opts)
return if !argv
- names = validate_pushes!(@env.pushes, argv, options)
+ name = validate_pushes!(@env.pushes, argv[0])
- names.each do |name|
- @logger.debug("'push' environment with strategy: `#{name}'")
- @env.push(name)
- end
+ @logger.debug("'push' environment with strategy: `#{name}'")
+ @env.push(name)
0
end
@@ -36,44 +30,37 @@ module VagrantPlugins
# if there are no pushes defined
# @raise Vagrant::Errors::PushStrategyNotProvided
# if there are multiple push strategies defined and none were specified
- # and `--all` was not given
# @raise Vagrant::Errors::PushStrategyNotDefined
- # if any of the given push names do not correspond to a push strategy
+ # if the given push name do not correspond to a push strategy
#
# @param [Array] pushes
# the list of pushes defined by the environment
- # @param [Array] names
- # the list of names provided by the user on the command line
- # @param [Hash] options
- # a list of options to pass to the validation
+ # @param [String] name
+ # the name provided by the user on the command line
#
- # @return [Array]
+ # @return [Symbol]
# the compiled list of pushes
#
- def validate_pushes!(pushes, names = [], options = {})
+ def validate_pushes!(pushes, name = nil)
if pushes.nil? || pushes.empty?
raise Vagrant::Errors::PushesNotDefined
end
- names = Array(names).flatten.compact.map(&:to_sym)
-
- if names.empty? || options[:all]
- if options[:all] || pushes.length == 1
- return pushes.map(&:to_sym)
+ if name.nil?
+ if pushes.length == 1
+ return pushes.first.to_sym
else
raise Vagrant::Errors::PushStrategyNotProvided, pushes: pushes
end
end
- names.each do |name|
- if !pushes.include?(name)
- raise Vagrant::Errors::PushStrategyNotDefined,
- name: name,
- pushes: pushes
- end
+ if !pushes.include?(name)
+ raise Vagrant::Errors::PushStrategyNotDefined,
+ name: name,
+ pushes: pushes
end
- return names
+ return name.to_sym
end
end
end
diff --git a/test/unit/plugins/commands/push/command_test.rb b/test/unit/plugins/commands/push/command_test.rb
index 292e2ee0e..113908ebf 100644
--- a/test/unit/plugins/commands/push/command_test.rb
+++ b/test/unit/plugins/commands/push/command_test.rb
@@ -31,29 +31,10 @@ describe VagrantPlugins::CommandPush::Command do
end
it "validates the pushes" do
- expect(subject).to receive(:validate_pushes!)
- .with(nil, argv, kind_of(Hash))
- .once
+ expect(subject).to receive(:validate_pushes!).once
subject.execute
end
- it "parses arguments" do
- list = ["noop", "ftp"]
- instance = described_class.new(list, env)
- expect(instance).to receive(:validate_pushes!)
- .with(nil, list, kind_of(Hash))
- .and_return([])
- instance.execute
- end
-
- it "parses options" do
- instance = described_class.new(["--all"], env)
- expect(instance).to receive(:validate_pushes!)
- .with(nil, argv, all: true)
- .and_return([])
- instance.execute
- end
-
it "delegates to Environment#push" do
expect(env).to receive(:push).once
subject.execute
@@ -93,21 +74,14 @@ describe VagrantPlugins::CommandPush::Command do
context "when that strategy is defined" do
it "returns that push" do
- expect(subject.validate_pushes!(pushes, :noop)).to eq([:noop])
+ expect(subject.validate_pushes!(pushes, :noop)).to eq(:noop)
end
end
end
context "when no strategy is given" do
it "returns the push" do
- expect(subject.validate_pushes!(pushes)).to eq([:noop])
- end
- end
-
- context "when --all is given" do
- it "returns the push" do
- expect(subject.validate_pushes!(pushes, [], all: true))
- .to eq([:noop])
+ expect(subject.validate_pushes!(pushes)).to eq(:noop)
end
end
end
@@ -127,32 +101,18 @@ describe VagrantPlugins::CommandPush::Command do
context "when that strategy is defined" do
it "returns the strategy" do
- expect(subject.validate_pushes!(pushes, :noop)).to eq([:noop])
- expect(subject.validate_pushes!(pushes, :ftp)).to eq([:ftp])
+ expect(subject.validate_pushes!(pushes, :noop)).to eq(:noop)
+ expect(subject.validate_pushes!(pushes, :ftp)).to eq(:ftp)
end
end
end
- context "when multiple strategies are given" do
- it "returns the pushes" do
- expect(subject.validate_pushes!(pushes, [:noop, :ftp]))
- .to eq([:noop, :ftp])
- end
- end
-
context "when no strategy is given" do
it "raises an exception" do
expect { subject.validate_pushes!(pushes) }
.to raise_error(Vagrant::Errors::PushStrategyNotProvided)
end
end
-
- context "when --all is given" do
- it "returns the pushes" do
- expect(subject.validate_pushes!(pushes, [], all: true))
- .to eq([:noop, :ftp])
- end
- end
end
end
end
diff --git a/website/docs/source/v2/push/index.html.md b/website/docs/source/v2/push/index.html.md
index 5f061862a..310039176 100644
--- a/website/docs/source/v2/push/index.html.md
+++ b/website/docs/source/v2/push/index.html.md
@@ -52,16 +52,6 @@ subcommand:
$ vagrant push staging
```
-Pushes will be run in the order you specify on the command line, **not the order
-they are specified in the `Vagrantfile`!**
-
-To execute all the Vagrant Push strategies, specify the `--all` flag with no
-other arguments:
-
-```shell
-$ vagrant push --all
-```
-
Vagrant Push is the easiest way to deploy your application. You can read more
in the documentation links on the sidebar.
From 78a4fdd6cd72c04a5f80c92d7684659243af7eca Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 2 Dec 2014 13:45:14 -0500
Subject: [PATCH 086/203] Be consistent
---
test/unit/plugins/commands/push/command_test.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/unit/plugins/commands/push/command_test.rb b/test/unit/plugins/commands/push/command_test.rb
index 113908ebf..8adfb2691 100644
--- a/test/unit/plugins/commands/push/command_test.rb
+++ b/test/unit/plugins/commands/push/command_test.rb
@@ -80,7 +80,7 @@ describe VagrantPlugins::CommandPush::Command do
end
context "when no strategy is given" do
- it "returns the push" do
+ it "returns the strategy" do
expect(subject.validate_pushes!(pushes)).to eq(:noop)
end
end
From 8df0b1848c6bd1c18e7923f2b0e154778f399b91 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 2 Dec 2014 13:45:45 -0500
Subject: [PATCH 087/203] Just return a symbol
---
test/unit/plugins/commands/push/command_test.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/unit/plugins/commands/push/command_test.rb b/test/unit/plugins/commands/push/command_test.rb
index 8adfb2691..06995d51d 100644
--- a/test/unit/plugins/commands/push/command_test.rb
+++ b/test/unit/plugins/commands/push/command_test.rb
@@ -25,7 +25,7 @@ describe VagrantPlugins::CommandPush::Command do
describe "#execute" do
before do
allow(subject).to receive(:validate_pushes!)
- .and_return([:noop])
+ .and_return(:noop)
allow(env).to receive(:pushes)
allow(env).to receive(:push)
end
From 9e5b587e66ee3b59ec8c8fbc30d6f59d931775bf Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 2 Dec 2014 13:46:22 -0500
Subject: [PATCH 088/203] Re-add TODO
---
plugins/commands/push/command.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/plugins/commands/push/command.rb b/plugins/commands/push/command.rb
index 5fde89175..d04e296fb 100644
--- a/plugins/commands/push/command.rb
+++ b/plugins/commands/push/command.rb
@@ -7,6 +7,7 @@ module VagrantPlugins
"deploys code in this environment to a configured destination"
end
+ # @todo support multiple strategies if requested by the community
def execute
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant push [strategy] [options]"
From 118e223c330b4e7308d41da3b333cd8615347525 Mon Sep 17 00:00:00 2001
From: Gilles Cornu
Date: Sun, 7 Dec 2014 10:40:21 +0100
Subject: [PATCH 089/203] provisioners/ansible: use Docker proxy when needed
Close #4071
Credits and best thanks to @jabclab
---
CHANGELOG.md | 1 +
plugins/provisioners/ansible/provisioner.rb | 18 ++++++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 42e753943..e99c4382b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -97,6 +97,7 @@ BUG FIXES:
- provisioners/ansible: Force `ssh` (OpenSSH) connection by default [GH-3396]
- provisioners/ansible: Don't use or modify `~/.ssh/known_hosts` file by default,
similarly to native vagrant commands [GH-3900]
+ - provisioners/ansible: Use intermediate Docker host when needed. [GH-4071]
- provisioners/docker: Get GPG key over SSL. [GH-4597]
- provisioners/docker: Search for docker binary in multiple places. [GH-4580]
- provisioners/salt: Highstate works properly with a master. [GH-4471]
diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb
index 49015997b..eea544abe 100644
--- a/plugins/provisioners/ansible/provisioner.rb
+++ b/plugins/provisioners/ansible/provisioner.rb
@@ -188,6 +188,24 @@ module VagrantPlugins
def get_ansible_ssh_args
ssh_options = []
+ # Use an SSH ProxyCommand when using the Docker provider with the intermediate host
+ if @machine.provider_name == :docker && machine.provider.host_vm?
+ docker_host_ssh_info = machine.provider.host_vm.ssh_info
+
+ proxy_cmd = "ssh #{docker_host_ssh_info[:username]}@#{docker_host_ssh_info[:host]}" +
+ " -p #{docker_host_ssh_info[:port]} -i #{docker_host_ssh_info[:private_key_path][0]}"
+
+ # Use same options than plugins/providers/docker/communicator.rb
+ # Note: this could be improved (DRY'ed) by sharing these settings.
+ proxy_cmd += " -o Compression=yes -o ConnectTimeout=5 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
+
+ proxy_cmd += " -o ForwardAgent=yes" if @ssh_info[:forward_agent]
+
+ proxy_cmd += " exec nc %h %p 2>/dev/null"
+
+ ssh_options << "-o ProxyCommand='#{ proxy_cmd }'"
+ end
+
# Don't access user's known_hosts file, except when host_key_checking is enabled.
ssh_options << "-o UserKnownHostsFile=/dev/null" unless config.host_key_checking
From fa7cd37e42216f7dda5a84dc99ba7f2da9bec67f Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Mon, 8 Dec 2014 16:54:19 -0800
Subject: [PATCH 090/203] Send the Atlas token
---
plugins/pushes/atlas/config.rb | 49 +++++++++--
plugins/pushes/atlas/locales/en.yml | 5 ++
plugins/pushes/atlas/push.rb | 1 +
test/unit/plugins/pushes/atlas/config_test.rb | 87 +++++++++++++++++++
test/unit/plugins/pushes/atlas/push_test.rb | 8 ++
website/docs/source/v2/push/atlas.html.md | 11 +++
6 files changed, 154 insertions(+), 7 deletions(-)
diff --git a/plugins/pushes/atlas/config.rb b/plugins/pushes/atlas/config.rb
index 9941da455..5c4a1a7cf 100644
--- a/plugins/pushes/atlas/config.rb
+++ b/plugins/pushes/atlas/config.rb
@@ -1,6 +1,19 @@
module VagrantPlugins
module AtlasPush
class Config < Vagrant.plugin("2", :config)
+ # The address of the Atlas server to upload to. By default this will
+ # be the public Atlas server.
+ #
+ # @return [String]
+ attr_accessor :address
+
+ # The Atlas token to use. If the user has run `vagrant login`, this will
+ # use that token. If the environment variable `ATLAS_TOKEN` is set, the
+ # uploader will use this value. By default, this is nil.
+ #
+ # @return [String, nil]
+ attr_accessor :token
+
# The name of the application to push to. This will be created (with
# user confirmation) if it doesn't already exist.
#
@@ -41,17 +54,12 @@ module VagrantPlugins
# @return [String]
attr_accessor :uploader_path
- # The address of the Atlas server to upload to. By default this will
- # be the public Atlas server.
- #
- # @return [String]
- attr_accessor :address
-
def initialize
+ @address = UNSET_VALUE
+ @token = UNSET_VALUE
@app = UNSET_VALUE
@dir = UNSET_VALUE
@vcs = UNSET_VALUE
- @address = UNSET_VALUE
@includes = []
@excludes = []
@uploader_path = UNSET_VALUE
@@ -66,6 +74,7 @@ module VagrantPlugins
def finalize!
@address = nil if @address == UNSET_VALUE
+ @token = nil if @token == UNSET_VALUE
@app = nil if @app == UNSET_VALUE
@dir = "." if @dir == UNSET_VALUE
@uploader_path = nil if @uploader_path == UNSET_VALUE
@@ -75,6 +84,15 @@ module VagrantPlugins
def validate(machine)
errors = _detected_errors
+ if missing?(@token)
+ token = token_from_vagrant_login(machine.env) || ENV["ATLAS_TOKEN"]
+ if missing?(token)
+ errors << I18n.t("atlas_push.errors.missing_token")
+ else
+ @token = token
+ end
+ end
+
if missing?(@app)
errors << I18n.t("atlas_push.errors.missing_attribute",
attribute: "app",
@@ -111,6 +129,23 @@ module VagrantPlugins
def missing?(obj)
obj.to_s.strip.empty?
end
+
+ # Attempt to load the token from disk using the vagrant-login plugin. If
+ # the constant is not defined, that means the user is operating in some
+ # bespoke and unsupported Ruby environment.
+ #
+ # @param [Vagrant::Environment] env
+ #
+ # @return [String, nil]
+ # the token, or nil if it does not exist
+ def token_from_vagrant_login(env)
+ if defined?(VagrantPlugins::Login::Client)
+ client = VagrantPlugins::Login::Client.new(env)
+ return client.token
+ end
+
+ nil
+ end
end
end
end
diff --git a/plugins/pushes/atlas/locales/en.yml b/plugins/pushes/atlas/locales/en.yml
index c54d59e67..3377f62dd 100644
--- a/plugins/pushes/atlas/locales/en.yml
+++ b/plugins/pushes/atlas/locales/en.yml
@@ -9,6 +9,11 @@ en:
config.push.define "atlas" do |push|
push.%{attribute} = "..."
end
+ missing_token: |-
+ Missing required configuration parameter 'token'. This is required for
+ Vagrant to securely communicate with your Atlas account.
+
+ To generate an access token, run 'vagrant login'.
uploader_not_found: |-
Vagrant was unable to find the Atlas uploader CLI. If your Vagrantfile
specifies the path explicitly with "uploader_path", then make sure that
diff --git a/plugins/pushes/atlas/push.rb b/plugins/pushes/atlas/push.rb
index 0b13f1bb3..24a6d28b0 100644
--- a/plugins/pushes/atlas/push.rb
+++ b/plugins/pushes/atlas/push.rb
@@ -27,6 +27,7 @@ module VagrantPlugins
cmd += config.includes.map { |v| ["-include", v] }
cmd += config.excludes.map { |v| ["-exclude", v] }
cmd += ["-address", config.address] if config.address
+ cmd += ["-token", config.token] if config.token
cmd << config.app
cmd << File.expand_path(config.dir, env.root_path)
Vagrant::Util::SafeExec.exec(uploader, *cmd.flatten)
diff --git a/test/unit/plugins/pushes/atlas/config_test.rb b/test/unit/plugins/pushes/atlas/config_test.rb
index 87411c472..e62a5b86e 100644
--- a/test/unit/plugins/pushes/atlas/config_test.rb
+++ b/test/unit/plugins/pushes/atlas/config_test.rb
@@ -12,6 +12,20 @@ describe VagrantPlugins::AtlasPush::Config do
let(:machine) { double("machine") }
+ describe "#address" do
+ it "defaults to nil" do
+ subject.finalize!
+ expect(subject.address).to be(nil)
+ end
+ end
+
+ describe "#token" do
+ it "defaults to nil" do
+ subject.finalize!
+ expect(subject.token).to be(nil)
+ end
+ end
+
describe "#app" do
it "defaults to nil" do
subject.finalize!
@@ -56,6 +70,79 @@ describe VagrantPlugins::AtlasPush::Config do
let(:result) { subject.validate(machine) }
let(:errors) { result["Atlas push"] }
+ context "when the token is missing" do
+ context "when a vagrant-login token exists" do
+ before do
+ allow(subject).to receive(:token_from_vagrant_login)
+ .and_return("token_from_vagrant_login")
+
+ allow(ENV).to receive(:[]).and_call_original
+ allow(ENV).to receive(:[])
+ .with("ATLAS_TOKEN").and_return("token_from_env")
+ end
+
+ it "uses the token in the Vagrantfile" do
+ subject.token = ""
+ subject.finalize!
+ expect(errors).to be_empty
+ expect(subject.token).to eq("token_from_vagrant_login")
+ end
+ end
+
+ context "when ATLAS_TOKEN is set in the environment" do
+ before do
+ allow(subject).to receive(:token_from_vagrant_login)
+ .and_return(nil)
+
+ allow(ENV).to receive(:[]).and_call_original
+ allow(ENV).to receive(:[])
+ .with("ATLAS_TOKEN").and_return("token_from_env")
+ end
+
+ it "uses the token in the environment" do
+ subject.token = ""
+ subject.finalize!
+ expect(errors).to be_empty
+ expect(subject.token).to eq("token_from_env")
+ end
+ end
+
+ context "when a token is given in the Vagrantfile" do
+ before do
+ allow(subject).to receive(:token_from_vagrant_login)
+ .and_return("token_from_vagrant_login")
+
+ allow(ENV).to receive(:[]).and_call_original
+ allow(ENV).to receive(:[])
+ .with("ATLAS_TOKEN").and_return("token_from_env")
+ end
+
+ it "uses the token in the Vagrantfile" do
+ subject.token = "token_from_vagrantfile"
+ subject.finalize!
+ expect(errors).to be_empty
+ expect(subject.token).to eq("token_from_vagrantfile")
+ end
+ end
+
+ context "when no token is given" do
+ before do
+ allow(subject).to receive(:token_from_vagrant_login)
+ .and_return(nil)
+
+ allow(ENV).to receive(:[]).and_call_original
+ allow(ENV).to receive(:[])
+ .with("ATLAS_TOKEN").and_return(nil)
+ end
+
+ it "returns an error" do
+ subject.token = ""
+ subject.finalize!
+ expect(errors).to include(I18n.t("atlas_push.errors.missing_token"))
+ end
+ end
+ end
+
context "when the app is missing" do
it "returns an error" do
subject.app = ""
diff --git a/test/unit/plugins/pushes/atlas/push_test.rb b/test/unit/plugins/pushes/atlas/push_test.rb
index b93231bb1..e7ffdebd5 100644
--- a/test/unit/plugins/pushes/atlas/push_test.rb
+++ b/test/unit/plugins/pushes/atlas/push_test.rb
@@ -91,6 +91,14 @@ describe VagrantPlugins::AtlasPush::Push do
config.address = "foo"
subject.execute("foo")
end
+
+ it "sends custom token" do
+ expect(Vagrant::Util::SafeExec).to receive(:exec).
+ with("foo", "-vcs", "-token", "atlas_token", app, env.root_path.to_s)
+
+ config.token = "atlas_token"
+ subject.execute("foo")
+ end
end
describe "#uploader_path" do
diff --git a/website/docs/source/v2/push/atlas.html.md b/website/docs/source/v2/push/atlas.html.md
index f001cfa51..e5679bbf2 100644
--- a/website/docs/source/v2/push/atlas.html.md
+++ b/website/docs/source/v2/push/atlas.html.md
@@ -35,6 +35,17 @@ The Vagrant Push Atlas strategy supports the following configuration options:
- `vcs` - If set to true, Vagrant will automatically use VCS data to determine
the files to upload. Uncommitted changes will not be deployed.
+Additionally, the following options are exposed for power users of the Vagrant
+Atlas push strategy. Most users will not require these options:
+
+- `address` - The address of the Atlas server to upload to. By default this will
+ be the public Atlas server.
+
+- `token` - The Atlas token to use. If the user has run `vagrant login`, this
+ will the token generated by that command. If the environment variable
+ `ATLAS_TOKEN` is set, the uploader will use this value. By default, this is
+ nil.
+
### Usage
From 2e4f854725ab915f2051755db87279c06d7611ef Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Mon, 8 Dec 2014 17:42:29 -0800
Subject: [PATCH 091/203] Vagrant Cloud -> Atlas
---
lib/vagrant/action/builtin/box_add.rb | 2 +-
lib/vagrant/shared_helpers.rb | 4 ++--
plugins/commands/box/command/add.rb | 2 +-
templates/locales/en.yml | 20 +++++++++----------
website/docs/source/v2/boxes.html.md | 4 ++--
website/docs/source/v2/boxes/base.html.md | 2 +-
website/docs/source/v2/boxes/format.html.md | 6 +++---
.../docs/source/v2/boxes/versioning.html.md | 6 +++---
website/docs/source/v2/cli/box.html.md | 8 ++++----
website/docs/source/v2/cli/login.html.md | 2 +-
.../source/v2/getting-started/boxes.html.md | 12 +++++------
.../source/v2/getting-started/share.html.md | 4 ++--
website/docs/source/v2/hyperv/usage.html.md | 2 +-
website/docs/source/v2/share/index.html.md | 2 +-
.../v2/vagrantfile/machine_settings.html.md | 6 +++---
15 files changed, 40 insertions(+), 42 deletions(-)
diff --git a/lib/vagrant/action/builtin/box_add.rb b/lib/vagrant/action/builtin/box_add.rb
index 554613b94..13688bae5 100644
--- a/lib/vagrant/action/builtin/box_add.rb
+++ b/lib/vagrant/action/builtin/box_add.rb
@@ -147,7 +147,7 @@ module Vagrant
# element is an authenticated URL.
# @param [Hash] env
# @param [Bool] expanded True if the metadata URL was expanded with
- # a Vagrant Cloud server URL.
+ # a Atlas server URL.
def add_from_metadata(url, env, expanded)
original_url = env[:box_url]
provider = env[:box_provider]
diff --git a/lib/vagrant/shared_helpers.rb b/lib/vagrant/shared_helpers.rb
index c2c52ae10..b195c36df 100644
--- a/lib/vagrant/shared_helpers.rb
+++ b/lib/vagrant/shared_helpers.rb
@@ -5,12 +5,12 @@ require "thread"
module Vagrant
@@global_lock = Mutex.new
- # This is the default endpoint of the Vagrant Cloud in
+ # This is the default endpoint of the Atlas in
# use. API calls will be made to this for various functions
# of Vagrant that may require remote access.
#
# @return [String]
- DEFAULT_SERVER_URL = "https://vagrantcloud.com"
+ DEFAULT_SERVER_URL = "https://atlas.hashicorp.com"
# This holds a global lock for the duration of the block. This should
# be invoked around anything that is modifying process state (such as
diff --git a/plugins/commands/box/command/add.rb b/plugins/commands/box/command/add.rb
index 0356ee298..d82d441a8 100644
--- a/plugins/commands/box/command/add.rb
+++ b/plugins/commands/box/command/add.rb
@@ -47,7 +47,7 @@ module VagrantPlugins
end
o.separator ""
- o.separator "The box descriptor can be the name of a box on Vagrant Cloud,"
+ o.separator "The box descriptor can be the name of a box on HashiCorp's Atlas,"
o.separator "or a URL, or a local .box file, or a local .json file containing"
o.separator "the catalog metadata."
o.separator ""
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index a201a3833..e28106a20 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -369,7 +369,7 @@ en:
provider. Double-check your requested provider to verify you didn't
simply misspell it.
- If you're adding a box from Vagrant Cloud, make sure the box is
+ If you're adding a box from HashiCorp's Atlas, make sure the box is
released.
Name: %{name}
@@ -388,7 +388,7 @@ en:
box_add_short_not_found: |-
The box '%{name}' could not be found or
could not be accessed in the remote catalog. If this is a private
- box on Vagrant Cloud, please verify you're logged in via
+ box on HashiCorp's Atlas, please verify you're logged in via
`vagrant login`. Also, please double-check the name. The expanded
URL and error message are shown below:
@@ -550,16 +550,14 @@ en:
%{versions}
box_server_not_set: |-
- A URL to a Vagrant Cloud server is not set, so boxes cannot
- be added with a shorthand ("mitchellh/precise64") format.
- You may also be seeing this error if you meant to type in
- a path to a box file which doesn't exist locally on your
- system.
+ A URL to an Atlas server is not set, so boxes cannot be added with a
+ shorthand ("mitchellh/precise64") format. You may also be seeing this
+ error if you meant to type in a path to a box file which doesn't exist
+ locally on your system.
- To set a URL to a Vagrant Cloud server, set the
- `VAGRANT_SERVER_URL` environmental variable. Or, if you
- meant to use a file path, make sure the path to the file
- is valid.
+ To set a URL to an Atlas server, set the `VAGRANT_SERVER_URL`
+ environmental variable. Or, if you meant to use a file path, make sure
+ the path to the file is valid.
box_update_multi_provider: |-
You requested to update the box '%{name}'. This box has
multiple providers. You must explicitly select a single
diff --git a/website/docs/source/v2/boxes.html.md b/website/docs/source/v2/boxes.html.md
index e3c1661de..491a5a631 100644
--- a/website/docs/source/v2/boxes.html.md
+++ b/website/docs/source/v2/boxes.html.md
@@ -14,7 +14,7 @@ boxes. You can read the documentation on the [vagrant box](/v2/cli/box.html)
command for more information.
The easiest way to use a box is to add a box from the
-[publicly available catalog of Vagrant boxes](https://vagrantcloud.com).
+[publicly available catalog of Vagrant boxes](https://atlas.hashicorp.com).
You can also add and share your own customized boxes on this website.
Boxes also support versioning so that members of your team using Vagrant
@@ -27,7 +27,7 @@ sub-pages in the navigation to the left.
## Discovering Boxes
The easiest way to find boxes is to look on the
-[public Vagrant box catalog](https://vagrantcloud.com)
+[public Vagrant box catalog](https://atlas.hashicorp.com)
for a box matching your use case. The catalog contains most major operating
systems as bases, as well as specialized boxes to get you up and running
quickly with LAMP stacks, Ruby, Python, etc.
diff --git a/website/docs/source/v2/boxes/base.html.md b/website/docs/source/v2/boxes/base.html.md
index e771187a0..61007ce92 100644
--- a/website/docs/source/v2/boxes/base.html.md
+++ b/website/docs/source/v2/boxes/base.html.md
@@ -239,7 +239,7 @@ provider-specific guides are linked to towards the top of this page.
You can distribute the box file however you'd like. However, if you want
to support versioning, putting multiple providers at a single URL, pushing
updates, analytics, and more, we recommend you add the box to
-[Vagrant Cloud](https://vagrantcloud.com).
+[HashiCorp's Atlas](https://atlas.hashicorp.com).
You can upload both public and private boxes to this service.
diff --git a/website/docs/source/v2/boxes/format.html.md b/website/docs/source/v2/boxes/format.html.md
index 0eb584026..3fa50479b 100644
--- a/website/docs/source/v2/boxes/format.html.md
+++ b/website/docs/source/v2/boxes/format.html.md
@@ -23,7 +23,7 @@ Today, there are two different components:
box file and so on.
* Box Catalog Metadata - This is a JSON document (typically exchanged
- during interactions with [Vagrant Cloud](https://vagrantcloud.com))
+ during interactions with [HashiCorp's Atlas](https://atlas.hashicorp.com))
that specifies the name of the box, a description, available
versions, available providers, and URLs to the actual box files
(next component) for each provider and version. If this catalog
@@ -78,8 +78,8 @@ providers from a single file, and more.
You don't need to manually make the metadata. If you
-have an account with
Vagrant Cloud, you
-can create boxes there, and Vagrant Cloud automatically creates
+have an account with
HashiCorp's Atlas, you
+can create boxes there, and HashiCorp's Atlas automatically creates
the metadata for you. The format is still documented here.
diff --git a/website/docs/source/v2/boxes/versioning.html.md b/website/docs/source/v2/boxes/versioning.html.md
index 61af2345a..dc4cf3e28 100644
--- a/website/docs/source/v2/boxes/versioning.html.md
+++ b/website/docs/source/v2/boxes/versioning.html.md
@@ -24,10 +24,10 @@ to update your own custom boxes with versions. That is covered in
`vagrant box list` only shows _installed_ versions of boxes. If you want
to see all available versions of a box, you'll have to find the box
-on [Vagrant Cloud](https://vagrantcloud.com). An easy way to find a box
-is to use the url `https://vagrantcloud.com/USER/BOX`. For example, for
+on [HashiCorp's Atlas](https://atlas.hashicorp.com). An easy way to find a box
+is to use the url `https://atlas.hashicorp.com/USER/BOX`. For example, for
the `hashicorp/precise64` box, you can find information about it at
-`https://vagrantcloud.com/hashicorp/precise64`.
+`https://atlas.hashicorp.com/hashicorp/precise64`.
You can check if the box you're using is outdated with `vagrant box outdated`.
This can check if the box in your current Vagrant environment is outdated
diff --git a/website/docs/source/v2/cli/box.html.md b/website/docs/source/v2/cli/box.html.md
index 0a5cff9fb..e3b39b4cb 100644
--- a/website/docs/source/v2/cli/box.html.md
+++ b/website/docs/source/v2/cli/box.html.md
@@ -26,10 +26,10 @@ This adds a box with the given address to Vagrant. The address can be
one of three things:
* A shorthand name from the
-[public catalog of available Vagrant images](https://vagrantcloud.com),
+[public catalog of available Vagrant images](https://atlas.hashicorp.com),
such as "hashicorp/precise64".
-* File path or HTTP URL to a box in a [catalog](https://vagrantcloud.com).
+* File path or HTTP URL to a box in a [catalog](https://atlas.hashicorp.com).
For HTTP, basic authentication is supported and `http_proxy` environmental
variables are respected. HTTPS is also supported.
@@ -93,8 +93,8 @@ you're not using a catalog).
to be specified.
-Checksums for versioned boxes or boxes from Vagrant Cloud:
-For boxes from Vagrant Cloud, the checksums are embedded in the metadata
+Checksums for versioned boxes or boxes from HashiCorp's Atlas:
+For boxes from HashiCorp's Atlas, the checksums are embedded in the metadata
of the box. The metadata itself is served over TLS and its format is validated.
diff --git a/website/docs/source/v2/cli/login.html.md b/website/docs/source/v2/cli/login.html.md
index 5e2e56065..a984cc77d 100644
--- a/website/docs/source/v2/cli/login.html.md
+++ b/website/docs/source/v2/cli/login.html.md
@@ -8,7 +8,7 @@ sidebar_current: "cli-login"
**Command: `vagrant login`**
The login command is used to authenticate with a
-[Vagrant Cloud](https://vagrantcloud.com) server. Logging is only
+[HashiCorp's Atlas](https://atlas.hashicorp.com) server. Logging is only
necessary if you're accessing protected boxes or using
[Vagrant Share](/v2/share/index.html).
diff --git a/website/docs/source/v2/getting-started/boxes.html.md b/website/docs/source/v2/getting-started/boxes.html.md
index b16aa893e..6a64f8a71 100644
--- a/website/docs/source/v2/getting-started/boxes.html.md
+++ b/website/docs/source/v2/getting-started/boxes.html.md
@@ -27,8 +27,8 @@ $ vagrant box add hashicorp/precise32
```
This will download the box named "hashicorp/precise32" from
-[Vagrant Cloud](https://vagrantcloud.com), a place where you can find
-and host boxes. While it is easiest to download boxes from Vagrant Cloud
+[HashiCorp's Atlas](https://atlas.hashicorp.com), a place where you can find
+and host boxes. While it is easiest to download boxes from HashiCorp's Atlas
you can also add boxes from a local file, custom URL, etc.
Added boxes can be re-used by multiple projects. Each project uses a box
@@ -64,11 +64,11 @@ For the remainder of this getting started guide, we'll only use the
this getting started guide, the first question you'll probably have is
"where do I find more boxes?"
-The best place to find more boxes is [Vagrant Cloud](https://vagrantcloud.com).
-Vagrant Cloud has a public directory of freely available boxes that
-run various platforms and technologies. Vagrant Cloud also has a great search
+The best place to find more boxes is [HashiCorp's Atlas](https://atlas.hashicorp.com).
+HashiCorp's Atlas has a public directory of freely available boxes that
+run various platforms and technologies. HashiCorp's Atlas also has a great search
feature to allow you to find the box you care about.
-In addition to finding free boxes, Vagrant Cloud lets you host your own
+In addition to finding free boxes, HashiCorp's Atlas lets you host your own
boxes, as well as private boxes if you intend on creating boxes for your
own organization.
diff --git a/website/docs/source/v2/getting-started/share.html.md b/website/docs/source/v2/getting-started/share.html.md
index 96c6ffe6a..694bd5d15 100644
--- a/website/docs/source/v2/getting-started/share.html.md
+++ b/website/docs/source/v2/getting-started/share.html.md
@@ -15,10 +15,10 @@ Vagrant Share lets you share your Vagrant environment to anyone around the
world. It will give you a URL that will route directly to your Vagrant
environment from any device in the world that is connected to the internet.
-## Login to Vagrant Cloud
+## Login to HashiCorp's Atlas
Before being able to share your Vagrant environment, you'll need an account on
-[Vagrant Cloud](https://vagrantcloud.com). Don't worry, it's free.
+[HashiCorp's Atlas](https://atlas.hashicorp.com). Don't worry, it's free.
Once you have an account, log in using `vagrant login`:
diff --git a/website/docs/source/v2/hyperv/usage.html.md b/website/docs/source/v2/hyperv/usage.html.md
index 7f3d9ccbe..e91c7e92e 100644
--- a/website/docs/source/v2/hyperv/usage.html.md
+++ b/website/docs/source/v2/hyperv/usage.html.md
@@ -17,5 +17,5 @@ admin rights. Vagrant will show you an error if it doesn't have the proper
permissions.
Boxes for Hyper-V can be easily found on
-[Vagrant Cloud](https://vagrantcloud.com). To get started, you might
+[HashiCorp's Atlas](https://atlas.hashicorp.com). To get started, you might
want to try the `hashicorp/precise64` box.
diff --git a/website/docs/source/v2/share/index.html.md b/website/docs/source/v2/share/index.html.md
index 078fd5e59..20fde2781 100644
--- a/website/docs/source/v2/share/index.html.md
+++ b/website/docs/source/v2/share/index.html.md
@@ -34,4 +34,4 @@ to the left. We also have a section where we go into detail about the
security implications of this feature.
Vagrant Share requires an account with
-[Vagrant Cloud](https://vagrantcloud.com) to be used.
+[HashiCorp's Atlas](https://atlas.hashicorp.com) to be used.
diff --git a/website/docs/source/v2/vagrantfile/machine_settings.html.md b/website/docs/source/v2/vagrantfile/machine_settings.html.md
index a6f69c194..8ea060de5 100644
--- a/website/docs/source/v2/vagrantfile/machine_settings.html.md
+++ b/website/docs/source/v2/vagrantfile/machine_settings.html.md
@@ -20,7 +20,7 @@ for the machine to boot and be accessible. By default this is 300 seconds.
`config.vm.box` - This configures what [box](/v2/boxes.html) the
machine will be brought up against. The value here should be the name
of an installed box or a shorthand name of a box in
-[Vagrant Cloud](https://vagrantcloud.com).
+[HashiCorp's Atlas](https://atlas.hashicorp.com).
@@ -28,7 +28,7 @@ of an installed box or a shorthand name of a box in
the configured box on every `vagrant up`. If an update is found, Vagrant
will tell the user. By default this is true. Updates will only be checked
for boxes that properly support updates (boxes from
-[Vagrant Cloud](https://vagrantcloud.com)
+[HashiCorp's Atlas](https://atlas.hashicorp.com)
or some other versioned box).
@@ -74,7 +74,7 @@ URL, then SSL certs will be verified.
`config.vm.box_url` - The URL that the configured box can be found at.
-If `config.vm.box` is a shorthand to a box in [Vagrant Cloud](https://vagrantcloud.com)
+If `config.vm.box` is a shorthand to a box in [HashiCorp's Atlas](https://atlas.hashicorp.com)
then this value doesn't need to be specified. Otherwise, it should
point to the proper place where the box can be found if it isn't
installed.
From b973186cb595680c54d55268cf6fcd0c04274ede Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Mon, 8 Dec 2014 17:42:00 -0800
Subject: [PATCH 092/203] Add vagrant-login to core ;)
---
plugins/commands/login/client.rb | 81 +++++++++++++
plugins/commands/login/command.rb | 83 +++++++++++++
plugins/commands/login/errors.rb | 13 +++
plugins/commands/login/locales/en.yml | 26 +++++
.../login/middleware/add_authentication.rb | 35 ++++++
plugins/commands/login/plugin.rb | 35 ++++++
test/unit/base.rb | 1 +
.../plugins/commands/login/client_test.rb | 109 ++++++++++++++++++
.../middleware/add_authentication_test.rb | 64 ++++++++++
vagrant.gemspec | 2 +
10 files changed, 449 insertions(+)
create mode 100644 plugins/commands/login/client.rb
create mode 100644 plugins/commands/login/command.rb
create mode 100644 plugins/commands/login/errors.rb
create mode 100644 plugins/commands/login/locales/en.yml
create mode 100644 plugins/commands/login/middleware/add_authentication.rb
create mode 100644 plugins/commands/login/plugin.rb
create mode 100644 test/unit/plugins/commands/login/client_test.rb
create mode 100644 test/unit/plugins/commands/login/middleware/add_authentication_test.rb
diff --git a/plugins/commands/login/client.rb b/plugins/commands/login/client.rb
new file mode 100644
index 000000000..01ba7649a
--- /dev/null
+++ b/plugins/commands/login/client.rb
@@ -0,0 +1,81 @@
+require "rest_client"
+
+module VagrantPlugins
+ module LoginCommand
+ class Client
+ # Initializes a login client with the given Vagrant::Environment.
+ #
+ # @param [Vagrant::Environment] env
+ def initialize(env)
+ @env = env
+ end
+
+ # Removes the token, effectively logging the user out.
+ def clear_token
+ token_path.delete if token_path.file?
+ end
+
+ # Checks if the user is logged in by verifying their authentication
+ # token.
+ #
+ # @return [Boolean]
+ def logged_in?
+ token = self.token
+ return false if !token
+
+ url = "#{Vagrant.server_url}/api/v1/authenticate" +
+ "?access_token=#{token}"
+ RestClient.get(url, content_type: :json)
+ true
+ rescue RestClient::Unauthorized
+ false
+ rescue SocketError
+ raise Errors::ServerUnreachable, url: Vagrant.server_url.to_s
+ end
+
+ # Login logs a user in and returns the token for that user. The token
+ # is _not_ stored unless {#store_token} is called.
+ #
+ # @param [String] user
+ # @param [String] pass
+ # @return [String] token The access token, or nil if auth failed.
+ def login(user, pass)
+ url = "#{Vagrant.server_url}/api/v1/authenticate"
+ request = { "user" => { "login" => user, "password" => pass } }
+ response = RestClient.post(
+ url, JSON.dump(request), content_type: :json)
+ data = JSON.load(response.to_s)
+ data["token"]
+ rescue RestClient::Unauthorized
+ return nil
+ rescue SocketError
+ raise Errors::ServerUnreachable, url: Vagrant.server_url.to_s
+ end
+
+ # Stores the given token locally, removing any previous tokens.
+ #
+ # @param [String] token
+ def store_token(token)
+ token_path.open("w") do |f|
+ f.write(token)
+ end
+ nil
+ end
+
+ # Reads the access token if there is one, or returns nil otherwise.
+ #
+ # @return [String]
+ def token
+ token_path.read
+ rescue Errno::ENOENT
+ return nil
+ end
+
+ protected
+
+ def token_path
+ @env.data_dir.join("vagrant_login_token")
+ end
+ end
+ end
+end
diff --git a/plugins/commands/login/command.rb b/plugins/commands/login/command.rb
new file mode 100644
index 000000000..e16b1afaf
--- /dev/null
+++ b/plugins/commands/login/command.rb
@@ -0,0 +1,83 @@
+module VagrantPlugins
+ module LoginCommand
+ class Command < Vagrant.plugin("2", "command")
+ def self.synopsis
+ "log in to HashiCorp's Atlas"
+ end
+
+ def execute
+ options = {}
+
+ opts = OptionParser.new do |o|
+ o.banner = "Usage: vagrant login"
+ o.separator ""
+ o.on("-c", "--check", "Only checks if you're logged in") do |c|
+ options[:check] = c
+ end
+
+ o.on("-k", "--logout", "Logs you out if you're logged in") do |k|
+ options[:logout] = k
+ end
+ end
+
+ # Parse the options
+ argv = parse_options(opts)
+ return if !argv
+
+ @client = Client.new(@env)
+
+ # Determine what task we're actually taking based on flags
+ if options[:check]
+ return execute_check
+ elsif options[:logout]
+ return execute_logout
+ end
+
+ # Let the user know what is going on.
+ @env.ui.output(I18n.t("login_command.command_header") + "\n")
+
+ # If it is a private cloud installation, show that
+ if Vagrant.server_url != Vagrant::DEFAULT_SERVER_URL
+ @env.ui.output("Atlas URL: #{Vagrant.server_url}")
+ end
+
+ # Ask for the username
+ login = nil
+ password = nil
+ while !login
+ login = @env.ui.ask("Atlas Username: ")
+ end
+
+ while !password
+ password = @env.ui.ask("Password (will be hidden): ", echo: false)
+ end
+
+ token = @client.login(login, password)
+ if !token
+ @env.ui.error(I18n.t("login_command.invalid_login"))
+ return 1
+ end
+
+ @client.store_token(token)
+ @env.ui.success(I18n.t("login_command.logged_in"))
+ 0
+ end
+
+ def execute_check
+ if @client.logged_in?
+ @env.ui.success(I18n.t("login_command.check_logged_in"))
+ return 0
+ else
+ @env.ui.error(I18n.t("login_command.check_not_logged_in"))
+ return 1
+ end
+ end
+
+ def execute_logout
+ @client.clear_token
+ @env.ui.success(I18n.t("login_command.logged_out"))
+ return 0
+ end
+ end
+ end
+end
diff --git a/plugins/commands/login/errors.rb b/plugins/commands/login/errors.rb
new file mode 100644
index 000000000..a6888b597
--- /dev/null
+++ b/plugins/commands/login/errors.rb
@@ -0,0 +1,13 @@
+module VagrantPlugins
+ module LoginCommand
+ module Errors
+ class Error < Vagrant::Errors::VagrantError
+ error_namespace("login_command.errors")
+ end
+
+ class ServerUnreachable < Error
+ error_key(:server_unreachable)
+ end
+ end
+ end
+end
diff --git a/plugins/commands/login/locales/en.yml b/plugins/commands/login/locales/en.yml
new file mode 100644
index 000000000..b62b24196
--- /dev/null
+++ b/plugins/commands/login/locales/en.yml
@@ -0,0 +1,26 @@
+en:
+ login_command:
+ errors:
+ server_unreachable: |-
+ The Atlas server is not currently accepting connections. Please check
+ your network connection and try again later.
+
+ check_logged_in: |-
+ You are already logged in.
+ check_not_logged_in: |-
+ You are not currently logged in. Please run `vagrant login` and provide
+ your login information to authenticate.
+ command_header: |-
+ In a moment we will ask for your username and password to HashiCorp's
+ Atlas. After authenticating, we will store an access token locally on
+ disk. Your login details will be transmitted over a secure connection, and
+ are never stored on disk locally.
+
+ If you do not have an Atlas account, sign up at
+ https://atlas.hashicorp.com.
+ invalid_login: |-
+ Invalid username or password. Please try again.
+ logged_in: |-
+ You are now logged in.
+ logged_out: |-
+ You are logged out.
diff --git a/plugins/commands/login/middleware/add_authentication.rb b/plugins/commands/login/middleware/add_authentication.rb
new file mode 100644
index 000000000..bfb7dd46b
--- /dev/null
+++ b/plugins/commands/login/middleware/add_authentication.rb
@@ -0,0 +1,35 @@
+require "uri"
+
+require_relative "../client"
+
+module VagrantPlugins
+ module LoginCommand
+ class AddAuthentication
+ def initialize(app, env)
+ @app = app
+ end
+
+ def call(env)
+ client = Client.new(env[:env])
+ token = client.token
+
+ if token && Vagrant.server_url
+ server_uri = URI.parse(Vagrant.server_url)
+
+ env[:box_urls].map! do |url|
+ u = URI.parse(url)
+ if u.host == server_uri.host
+ u.query ||= ""
+ u.query += "&" if u.query != ""
+ u.query += "access_token=#{token}"
+ end
+
+ u.to_s
+ end
+ end
+
+ @app.call(env)
+ end
+ end
+ end
+end
diff --git a/plugins/commands/login/plugin.rb b/plugins/commands/login/plugin.rb
new file mode 100644
index 000000000..10ab352cf
--- /dev/null
+++ b/plugins/commands/login/plugin.rb
@@ -0,0 +1,35 @@
+require "vagrant"
+
+module VagrantPlugins
+ module LoginCommand
+ autoload :Client, File.expand_path("../client", __FILE__)
+ autoload :Errors, File.expand_path("../errors", __FILE__)
+
+ class Plugin < Vagrant.plugin("2")
+ name "vagrant-login"
+ description <<-DESC
+ Provides the login command and internal API access to Atlas.
+ DESC
+
+ command(:login) do
+ require_relative "login"
+ init!
+ Push
+ end
+
+ action_hook(:cloud_authenticated_boxes, :authenticate_box_url) do |hook|
+ require_relative "middleware/add_authentication"
+ hook.prepend(AddAuthentication)
+ end
+
+ protected
+
+ def self.init!
+ return if defined?(@_init)
+ I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
+ I18n.reload!
+ @_init = true
+ end
+ end
+ end
+end
diff --git a/test/unit/base.rb b/test/unit/base.rb
index c7b11b958..e3c68c099 100644
--- a/test/unit/base.rb
+++ b/test/unit/base.rb
@@ -4,6 +4,7 @@ require "rubygems"
# Gems
require "checkpoint"
require "rspec/autorun"
+require "webmock/rspec"
# Require Vagrant itself so we can reference the proper
# classes to test.
diff --git a/test/unit/plugins/commands/login/client_test.rb b/test/unit/plugins/commands/login/client_test.rb
new file mode 100644
index 000000000..cad502ccf
--- /dev/null
+++ b/test/unit/plugins/commands/login/client_test.rb
@@ -0,0 +1,109 @@
+require File.expand_path("../../../../base", __FILE__)
+
+require Vagrant.source_root.join("plugins/commands/login/command")
+
+describe VagrantPlugins::LoginCommand::Client do
+ include_context "unit"
+
+ let(:env) { isolated_environment.create_vagrant_env }
+
+ subject { described_class.new(env) }
+
+ describe "#logged_in?" do
+ it "quickly returns false if no token is set" do
+ expect(subject).to_not be_logged_in
+ end
+
+ it "returns true if the endpoint returns 200" do
+ subject.store_token("foo")
+
+ response = {
+ "token" => "baz",
+ }
+
+ headers = { "Content-Type" => "application/json" }
+ url = "#{Vagrant.server_url}/api/v1/authenticate?access_token=foo"
+ stub_request(:get, url).
+ with(headers: headers).
+ to_return(status: 200, body: JSON.dump(response))
+
+ expect(subject).to be_logged_in
+ end
+
+ it "returns false if 401 is returned" do
+ subject.store_token("foo")
+
+ url = "#{Vagrant.server_url}/api/v1/authenticate?access_token=foo"
+ stub_request(:get, url).
+ to_return(status: 401, body: "")
+
+ expect(subject).to_not be_logged_in
+ end
+
+ it "raises an exception if it can't reach the sever" do
+ subject.store_token("foo")
+
+ url = "#{Vagrant.server_url}/api/v1/authenticate?access_token=foo"
+ stub_request(:get, url).to_raise(SocketError)
+
+ expect { subject.logged_in? }.
+ to raise_error(VagrantPlugins::LoginCommand::Errors::ServerUnreachable)
+ end
+ end
+
+ describe "#login" do
+ it "returns the access token after successful login" do
+ request = {
+ "user" => {
+ "login" => "foo",
+ "password" => "bar",
+ },
+ }
+
+ response = {
+ "token" => "baz",
+ }
+
+ headers = { "Content-Type" => "application/json" }
+
+ stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
+ with(body: JSON.dump(request), headers: headers).
+ to_return(status: 200, body: JSON.dump(response))
+
+ expect(subject.login("foo", "bar")).to eq("baz")
+ end
+
+ it "returns nil on bad login" do
+ stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
+ to_return(status: 401, body: "")
+
+ expect(subject.login("foo", "bar")).to be_nil
+ end
+
+ it "raises an exception if it can't reach the sever" do
+ stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
+ to_raise(SocketError)
+
+ expect { subject.login("foo", "bar") }.
+ to raise_error(VagrantPlugins::LoginCommand::Errors::ServerUnreachable)
+ end
+ end
+
+ describe "#token, #store_token, #clear_token" do
+ it "returns nil if there is no token" do
+ expect(subject.token).to be_nil
+ end
+
+ it "stores the token and can re-access it" do
+ subject.store_token("foo")
+ expect(subject.token).to eq("foo")
+ expect(described_class.new(env).token).to eq("foo")
+ end
+
+ it "deletes the token" do
+ subject.store_token("foo")
+ subject.clear_token
+ expect(subject.token).to be_nil
+ end
+ end
+end
diff --git a/test/unit/plugins/commands/login/middleware/add_authentication_test.rb b/test/unit/plugins/commands/login/middleware/add_authentication_test.rb
new file mode 100644
index 000000000..826e5d46b
--- /dev/null
+++ b/test/unit/plugins/commands/login/middleware/add_authentication_test.rb
@@ -0,0 +1,64 @@
+require File.expand_path("../../../../../base", __FILE__)
+
+require Vagrant.source_root.join("plugins/commands/login/middleware/add_authentication")
+
+describe VagrantPlugins::LoginCommand::AddAuthentication do
+ include_context "unit"
+
+ let(:app) { lambda { |env| } }
+ let(:env) { {
+ env: iso_env,
+ } }
+
+ let(:iso_env) { isolated_environment.create_vagrant_env }
+ let(:server_url) { "http://foo.com" }
+
+ subject { described_class.new(app, env) }
+
+ before do
+ allow(Vagrant).to receive(:server_url).and_return(server_url)
+ end
+
+ describe "#call" do
+ it "does nothing if we have no server set" do
+ allow(Vagrant).to receive(:server_url).and_return(nil)
+ VagrantPlugins::LoginCommand::Client.new(iso_env).store_token("foo")
+
+ original = ["foo", "#{server_url}/bar"]
+ env[:box_urls] = original.dup
+
+ subject.call(env)
+
+ expect(env[:box_urls]).to eq(original)
+ end
+
+ it "does nothing if we aren't logged in" do
+ original = ["foo", "#{server_url}/bar"]
+ env[:box_urls] = original.dup
+
+ subject.call(env)
+
+ expect(env[:box_urls]).to eq(original)
+ end
+
+ it "appends the access token to the URL of server URLs" do
+ token = "foobarbaz"
+ VagrantPlugins::LoginCommand::Client.new(iso_env).store_token(token)
+
+ original = [
+ "http://google.com/box.box",
+ "#{server_url}/foo.box",
+ "#{server_url}/bar.box?arg=true",
+ ]
+
+ expected = original.dup
+ expected[1] = "#{original[1]}?access_token=#{token}"
+ expected[2] = "#{original[2]}&access_token=#{token}"
+
+ env[:box_urls] = original.dup
+ subject.call(env)
+
+ expect(env[:box_urls]).to eq(expected)
+ end
+ end
+end
diff --git a/vagrant.gemspec b/vagrant.gemspec
index 23931940b..a2115b055 100644
--- a/vagrant.gemspec
+++ b/vagrant.gemspec
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
s.add_dependency "net-sftp", "~> 2.1"
s.add_dependency "net-scp", "~> 1.1.0"
s.add_dependency "rb-kqueue", "~> 0.2.0"
+ s.add_dependency "rest-client", "~> 1.7"
s.add_dependency "wdm", "~> 0.1.0"
s.add_dependency "winrm", "~> 1.1.3"
@@ -34,6 +35,7 @@ Gem::Specification.new do |s|
s.add_development_dependency "rake"
s.add_development_dependency "rspec", "~> 2.14.0"
+ s.add_development_dependency "webmock", "~> 1.20"
s.add_development_dependency "fake_ftp", "~> 0.1"
# The following block of code determines the files that should be included
From 3d8a1ec3fc21541e6840eafe0bc1f245c3250a96 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Mon, 8 Dec 2014 17:48:22 -0800
Subject: [PATCH 093/203] Fix some rename shit
---
plugins/commands/login/plugin.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/plugins/commands/login/plugin.rb b/plugins/commands/login/plugin.rb
index 10ab352cf..efb84a556 100644
--- a/plugins/commands/login/plugin.rb
+++ b/plugins/commands/login/plugin.rb
@@ -12,9 +12,9 @@ module VagrantPlugins
DESC
command(:login) do
- require_relative "login"
+ require_relative "command"
init!
- Push
+ Command
end
action_hook(:cloud_authenticated_boxes, :authenticate_box_url) do |hook|
From 62065e013a928772b9ccb8e594056f096bbd182d Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Mon, 8 Dec 2014 18:24:01 -0800
Subject: [PATCH 094/203] Read and return login errors from Atlas
---
plugins/commands/login/client.rb | 50 +++++++++++++++++----------
plugins/commands/login/errors.rb | 4 +++
plugins/commands/login/locales/en.yml | 4 +++
3 files changed, 40 insertions(+), 18 deletions(-)
diff --git a/plugins/commands/login/client.rb b/plugins/commands/login/client.rb
index 01ba7649a..f06772be9 100644
--- a/plugins/commands/login/client.rb
+++ b/plugins/commands/login/client.rb
@@ -23,14 +23,12 @@ module VagrantPlugins
token = self.token
return false if !token
- url = "#{Vagrant.server_url}/api/v1/authenticate" +
- "?access_token=#{token}"
- RestClient.get(url, content_type: :json)
- true
- rescue RestClient::Unauthorized
- false
- rescue SocketError
- raise Errors::ServerUnreachable, url: Vagrant.server_url.to_s
+ with_error_handling do
+ url = "#{Vagrant.server_url}/api/v1/authenticate" +
+ "?access_token=#{token}"
+ RestClient.get(url, content_type: :json)
+ true
+ end
end
# Login logs a user in and returns the token for that user. The token
@@ -40,16 +38,14 @@ module VagrantPlugins
# @param [String] pass
# @return [String] token The access token, or nil if auth failed.
def login(user, pass)
- url = "#{Vagrant.server_url}/api/v1/authenticate"
- request = { "user" => { "login" => user, "password" => pass } }
- response = RestClient.post(
- url, JSON.dump(request), content_type: :json)
- data = JSON.load(response.to_s)
- data["token"]
- rescue RestClient::Unauthorized
- return nil
- rescue SocketError
- raise Errors::ServerUnreachable, url: Vagrant.server_url.to_s
+ with_error_handling do
+ url = "#{Vagrant.server_url}/api/v1/authenticate"
+ request = { "user" => { "login" => user, "password" => pass } }
+ response = RestClient.post(
+ url, JSON.dump(request), content_type: :json)
+ data = JSON.load(response.to_s)
+ data["token"]
+ end
end
# Stores the given token locally, removing any previous tokens.
@@ -73,6 +69,24 @@ module VagrantPlugins
protected
+ def with_error_handling(&block)
+ yield
+ rescue RestClient::Unauthorized
+ false
+ rescue RestClient::NotAcceptable => e
+ begin
+ errors = JSON.parse(e.response)["errors"]
+ .map { |h| h["message"] }
+ .join("\n")
+
+ raise Errors::ServerError, errors: errors
+ rescue JSON::ParserError; end
+
+ raise "An unexpected error occurred: #{e.inspect}"
+ rescue SocketError
+ raise Errors::ServerUnreachable, url: Vagrant.server_url.to_s
+ end
+
def token_path
@env.data_dir.join("vagrant_login_token")
end
diff --git a/plugins/commands/login/errors.rb b/plugins/commands/login/errors.rb
index a6888b597..614c37cf6 100644
--- a/plugins/commands/login/errors.rb
+++ b/plugins/commands/login/errors.rb
@@ -5,6 +5,10 @@ module VagrantPlugins
error_namespace("login_command.errors")
end
+ class ServerError < Error
+ error_key(:server_error)
+ end
+
class ServerUnreachable < Error
error_key(:server_unreachable)
end
diff --git a/plugins/commands/login/locales/en.yml b/plugins/commands/login/locales/en.yml
index b62b24196..51020df1d 100644
--- a/plugins/commands/login/locales/en.yml
+++ b/plugins/commands/login/locales/en.yml
@@ -1,6 +1,10 @@
en:
login_command:
errors:
+ server_error: |-
+ The Atlas server responded with an not-OK response:
+
+ %{errors}
server_unreachable: |-
The Atlas server is not currently accepting connections. Please check
your network connection and try again later.
From bb7b954a5feaa613d2ce91f4e19080a71b176666 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Mon, 8 Dec 2014 22:06:41 -0800
Subject: [PATCH 095/203] Use the new namespace in Atlas config
---
plugins/pushes/atlas/config.rb | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/plugins/pushes/atlas/config.rb b/plugins/pushes/atlas/config.rb
index 5c4a1a7cf..d4d2da2c5 100644
--- a/plugins/pushes/atlas/config.rb
+++ b/plugins/pushes/atlas/config.rb
@@ -139,12 +139,8 @@ module VagrantPlugins
# @return [String, nil]
# the token, or nil if it does not exist
def token_from_vagrant_login(env)
- if defined?(VagrantPlugins::Login::Client)
- client = VagrantPlugins::Login::Client.new(env)
- return client.token
- end
-
- nil
+ client = VagrantPlugins::LoginCommand::Client.new(env)
+ client.token
end
end
end
From 9ec16774ace424cdf8c2d7d60a7c90c2ea9b3e7d Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 9 Dec 2014 00:08:23 -0800
Subject: [PATCH 096/203] Fix failing specs
---
test/unit/plugins/commands/login/client_test.rb | 2 +-
test/unit/plugins/pushes/atlas/config_test.rb | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/unit/plugins/commands/login/client_test.rb b/test/unit/plugins/commands/login/client_test.rb
index cad502ccf..7c9480442 100644
--- a/test/unit/plugins/commands/login/client_test.rb
+++ b/test/unit/plugins/commands/login/client_test.rb
@@ -77,7 +77,7 @@ describe VagrantPlugins::LoginCommand::Client do
stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
to_return(status: 401, body: "")
- expect(subject.login("foo", "bar")).to be_nil
+ expect(subject.login("foo", "bar")).to be(false)
end
it "raises an exception if it can't reach the sever" do
diff --git a/test/unit/plugins/pushes/atlas/config_test.rb b/test/unit/plugins/pushes/atlas/config_test.rb
index e62a5b86e..1600e967a 100644
--- a/test/unit/plugins/pushes/atlas/config_test.rb
+++ b/test/unit/plugins/pushes/atlas/config_test.rb
@@ -59,6 +59,7 @@ describe VagrantPlugins::AtlasPush::Config do
allow(machine).to receive(:env)
.and_return(double("env",
root_path: "",
+ data_dir: Pathname.new(""),
))
subject.app = "sethvargo/bacon"
From 4669a401f571241014dd306d21d4446fea009918 Mon Sep 17 00:00:00 2001
From: Kevin Bowling
Date: Tue, 9 Dec 2014 01:35:22 -0700
Subject: [PATCH 097/203] Allow listen 2.8
---
vagrant.gemspec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/vagrant.gemspec b/vagrant.gemspec
index 1981493ff..61c51df7b 100644
--- a/vagrant.gemspec
+++ b/vagrant.gemspec
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
s.add_dependency "childprocess", "~> 0.5.0"
s.add_dependency "erubis", "~> 2.7.0"
s.add_dependency "i18n", "~> 0.6.0"
- s.add_dependency "listen", "~> 2.7.11"
+ s.add_dependency "listen", ">= 2.7.11", "< 2.9.0"
s.add_dependency "hashicorp-checkpoint", "~> 0.1.1"
s.add_dependency "log4r", "~> 1.1.9", "< 1.1.11"
s.add_dependency "net-ssh", ">= 2.6.6", "< 2.10.0"
From d8b73fc31974fd190234a890a4c5bf82cccd57d3 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 9 Dec 2014 10:14:32 -0800
Subject: [PATCH 098/203] Add changelog entry for vagrant-login
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 53565b085..e0d9adb5b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ FEATURES:
providers are chosen before later ones. [GH-3812]
- If the default insecure keypair is used, Vagrant will automatically replace
it with a randomly generated keypair on first `vagrant up`. [GH-2608]
+ - Vagrant Login is now part of Vagrant core
- Chef Zero provisioner: Use Chef 11's "local" mode to run recipes against an
in-memory Chef Server
- Chef Apply provisioner: Specify inline Chef recipes and recipe snippets
From 2b8489f205ae20a87524f7f10d5c58d8453c0be6 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Tue, 9 Dec 2014 16:23:06 -0800
Subject: [PATCH 099/203] update CHANGELOG
---
CHANGELOG.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5111ccd0b..0804c529a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,10 @@ BREAKING CHANGES:
FEATURES:
+ - **Vagrant Push**: Vagrant can now deploy! `vagrant push` is a single
+ command to deploy your application. Deploy to Heroku, FTP, or
+ HashiCorp's commercial product Atlas. New push strategies can be
+ added with plugins.
- **Named provisioners**: Provisioners can now be named. This name is used
for output as well as `--provision-with` for better control.
- Default provider logic improved: Providers in `config.vm.provider` blocks
From ea8f6b8d04ce02fb7e0940c31b01c1ae3962d28c Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Tue, 9 Dec 2014 19:32:14 -0800
Subject: [PATCH 100/203] pushes/atlas: fix tests
---
test/unit/plugins/pushes/atlas/config_test.rb | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/test/unit/plugins/pushes/atlas/config_test.rb b/test/unit/plugins/pushes/atlas/config_test.rb
index 1600e967a..1b2695ba9 100644
--- a/test/unit/plugins/pushes/atlas/config_test.rb
+++ b/test/unit/plugins/pushes/atlas/config_test.rb
@@ -12,6 +12,10 @@ describe VagrantPlugins::AtlasPush::Config do
let(:machine) { double("machine") }
+ before do
+ subject.token = "foo"
+ end
+
describe "#address" do
it "defaults to nil" do
subject.finalize!
@@ -19,13 +23,6 @@ describe VagrantPlugins::AtlasPush::Config do
end
end
- describe "#token" do
- it "defaults to nil" do
- subject.finalize!
- expect(subject.token).to be(nil)
- end
- end
-
describe "#app" do
it "defaults to nil" do
subject.finalize!
From ae7fc545e1e60e2a8e14abcad5f72b90014a7d2b Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Tue, 9 Dec 2014 19:32:36 -0800
Subject: [PATCH 101/203] v1.7.0
---
CHANGELOG.md | 2 +-
version.txt | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0804c529a..f9f46eb3c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-## 1.7.0 (unreleased)
+## 1.7.0 (December 9, 2014)
BREAKING CHANGES:
diff --git a/version.txt b/version.txt
index c3da48456..bd8bf882d 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-1.7.0.dev
+1.7.0
From 6f535da011795cb373ac34cb8ce2868d4f198ea3 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Tue, 9 Dec 2014 19:55:25 -0800
Subject: [PATCH 102/203] Wrong version #
---
website/docs/source/v2/push/index.html.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/website/docs/source/v2/push/index.html.md b/website/docs/source/v2/push/index.html.md
index 310039176..62f696ea7 100644
--- a/website/docs/source/v2/push/index.html.md
+++ b/website/docs/source/v2/push/index.html.md
@@ -7,7 +7,7 @@ description: |-
# Vagrant Push
-As of version 1.8, Vagrant is capable of deploying or "pushing" application code
+As of version 1.7, Vagrant is capable of deploying or "pushing" application code
in the same directory as your Vagrantfile to a remote such as an FTP server or
[HashiCorp's Atlas][Atlas].
From ce037b6ff476421885095b19a0f6eeb59edce293 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Tue, 9 Dec 2014 20:38:05 -0800
Subject: [PATCH 103/203] website/www: bump
---
website/www/version.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/website/www/version.txt b/website/www/version.txt
index 60abf8d5d..b958192dc 100644
--- a/website/www/version.txt
+++ b/website/www/version.txt
@@ -1,4 +1,4 @@
This is just used to force a deploy on Heroku. Just update this number
whenever you want:
-10
+11
From ff987b19ec4bed99fe6e4e8d2aea865e4d54f0df Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Tue, 9 Dec 2014 23:20:08 -0800
Subject: [PATCH 104/203] Make rest-client dependency looser
---
vagrant.gemspec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/vagrant.gemspec b/vagrant.gemspec
index a2115b055..0afe7e766 100644
--- a/vagrant.gemspec
+++ b/vagrant.gemspec
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
s.add_dependency "net-sftp", "~> 2.1"
s.add_dependency "net-scp", "~> 1.1.0"
s.add_dependency "rb-kqueue", "~> 0.2.0"
- s.add_dependency "rest-client", "~> 1.7"
+ s.add_dependency "rest-client", ">= 1.6.0", "< 2.0"
s.add_dependency "wdm", "~> 0.1.0"
s.add_dependency "winrm", "~> 1.1.3"
From e65ae7b54363151d5f8ed66cdb5ae1a3b50bba1a Mon Sep 17 00:00:00 2001
From: Michael Dwyer
Date: Wed, 10 Dec 2014 10:56:30 -0600
Subject: [PATCH 105/203] Add back creation of mount point
Accidentally removed in ad4b30dd
---
plugins/guests/freebsd/cap/mount_nfs_folder.rb | 2 ++
1 file changed, 2 insertions(+)
diff --git a/plugins/guests/freebsd/cap/mount_nfs_folder.rb b/plugins/guests/freebsd/cap/mount_nfs_folder.rb
index a008ec3f4..58d8f785c 100644
--- a/plugins/guests/freebsd/cap/mount_nfs_folder.rb
+++ b/plugins/guests/freebsd/cap/mount_nfs_folder.rb
@@ -8,6 +8,8 @@ module VagrantPlugins
nfs_version_mount_option="-o nfsv#{opts[:nfs_version]}"
end
+ machine.communicate.sudo("mkdir -p #{opts[:guestpath]}", {shell: "sh"})
+
machine.communicate.sudo(
"mount -t nfs #{nfs_version_mount_option} " +
"'#{ip}:#{opts[:hostpath]}' '#{opts[:guestpath]}'", {shell: "sh"})
From 2a285d76551c7ceee79dd0370cc7bd1c8cac0100 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 10 Dec 2014 09:16:45 -0800
Subject: [PATCH 106/203] hosts/bad: escape regexp properly [GH-4922]
---
plugins/hosts/bsd/cap/nfs.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/hosts/bsd/cap/nfs.rb b/plugins/hosts/bsd/cap/nfs.rb
index b154ad19c..9fd1f7ef8 100644
--- a/plugins/hosts/bsd/cap/nfs.rb
+++ b/plugins/hosts/bsd/cap/nfs.rb
@@ -137,7 +137,7 @@ module VagrantPlugins
user = Process.uid
File.read("/etc/exports").lines.each do |line|
- if id = line[/^# VAGRANT-BEGIN:( #{user})? ([\.\/A-Za-z0-9-_]+?)$/, 2]
+ if id = line[/^# VAGRANT-BEGIN:( #{user})? ([\.\/A-Za-z0-9\-_]+?)$/, 2]
if valid_ids.include?(id)
logger.debug("Valid ID: #{id}")
else
From 2385305f6f30d2383a82590471bba420449cac2a Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 10 Dec 2014 09:26:31 -0800
Subject: [PATCH 107/203] core: Don't encode! since string might be frozen
---
lib/vagrant/util/subprocess.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/vagrant/util/subprocess.rb b/lib/vagrant/util/subprocess.rb
index dbb28ea97..278d68d01 100644
--- a/lib/vagrant/util/subprocess.rb
+++ b/lib/vagrant/util/subprocess.rb
@@ -25,7 +25,7 @@ module Vagrant
def initialize(*command)
@options = command.last.is_a?(Hash) ? command.pop : {}
@command = command.dup
- @command.each { |s| s.encode!(Encoding.default_external) }
+ @command.each { |s| s.encode(Encoding.default_external) }
@command[0] = Which.which(@command[0]) if !File.file?(@command[0])
if !@command[0]
raise Errors::CommandUnavailableWindows, file: command[0] if Platform.windows?
From 7d6a6cd2639d01b9f4887a378a1333cbbedb57de Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 10 Dec 2014 15:08:43 -0800
Subject: [PATCH 108/203] Read the ATLAS_TOKEN in vagrant-login
---
plugins/commands/login/client.rb | 16 ++-
.../plugins/commands/login/client_test.rb | 100 +++++++++++-------
2 files changed, 76 insertions(+), 40 deletions(-)
diff --git a/plugins/commands/login/client.rb b/plugins/commands/login/client.rb
index f06772be9..1e8381fe4 100644
--- a/plugins/commands/login/client.rb
+++ b/plugins/commands/login/client.rb
@@ -58,13 +58,21 @@ module VagrantPlugins
nil
end
- # Reads the access token if there is one, or returns nil otherwise.
+ # Reads the access token if there is one. This will first read the
+ # `ATLAS_TOKEN` environment variable and then fallback to the stored
+ # access token on disk.
#
# @return [String]
def token
- token_path.read
- rescue Errno::ENOENT
- return nil
+ if ENV["ATLAS_TOKEN"] && !ENV["ATLAS_TOKEN"].empty?
+ return ENV["ATLAS_TOKEN"]
+ end
+
+ if token_path.exist?
+ return token_path.read.strip
+ end
+
+ nil
end
protected
diff --git a/test/unit/plugins/commands/login/client_test.rb b/test/unit/plugins/commands/login/client_test.rb
index 7c9480442..fcdf1b902 100644
--- a/test/unit/plugins/commands/login/client_test.rb
+++ b/test/unit/plugins/commands/login/client_test.rb
@@ -5,49 +5,59 @@ require Vagrant.source_root.join("plugins/commands/login/command")
describe VagrantPlugins::LoginCommand::Client do
include_context "unit"
+ def stub_env(key, value = nil)
+ allow(ENV).to receive(:[]).and_call_original
+ allow(ENV).to receive(:[])
+ .with(key)
+ .and_return(value)
+ end
+
let(:env) { isolated_environment.create_vagrant_env }
subject { described_class.new(env) }
+ before do
+ stub_env("ATLAS_TOKEN", nil)
+ subject.clear_token
+ end
+
describe "#logged_in?" do
- it "quickly returns false if no token is set" do
- expect(subject).to_not be_logged_in
+ let(:url) { "#{Vagrant.server_url}/api/v1/authenticate?access_token=#{token}" }
+ let(:headers) { { "Content-Type" => "application/json" } }
+
+ before { allow(subject).to receive(:token).and_return(token) }
+
+ context "when there is no token" do
+ let(:token) { nil }
+
+ it "returns false" do
+ expect(subject.logged_in?).to be(false)
+ end
end
- it "returns true if the endpoint returns 200" do
- subject.store_token("foo")
+ context "when there is a token" do
+ let(:token) { "ABCD1234" }
- response = {
- "token" => "baz",
- }
+ it "returns true if the endpoint returns a 200" do
+ stub_request(:get, url)
+ .with(headers: headers)
+ .to_return(body: JSON.pretty_generate("token" => token))
+ expect(subject.logged_in?).to be(true)
+ end
- headers = { "Content-Type" => "application/json" }
- url = "#{Vagrant.server_url}/api/v1/authenticate?access_token=foo"
- stub_request(:get, url).
- with(headers: headers).
- to_return(status: 200, body: JSON.dump(response))
+ it "returns false if the endpoint returns a non-200" do
+ stub_request(:get, url)
+ .with(headers: headers)
+ .to_return(body: JSON.pretty_generate("bad" => true), status: 401)
+ expect(subject.logged_in?).to be(false)
+ end
- expect(subject).to be_logged_in
- end
-
- it "returns false if 401 is returned" do
- subject.store_token("foo")
-
- url = "#{Vagrant.server_url}/api/v1/authenticate?access_token=foo"
- stub_request(:get, url).
- to_return(status: 401, body: "")
-
- expect(subject).to_not be_logged_in
- end
-
- it "raises an exception if it can't reach the sever" do
- subject.store_token("foo")
-
- url = "#{Vagrant.server_url}/api/v1/authenticate?access_token=foo"
- stub_request(:get, url).to_raise(SocketError)
-
- expect { subject.logged_in? }.
- to raise_error(VagrantPlugins::LoginCommand::Errors::ServerUnreachable)
+ it "raises an exception if the server cannot be found" do
+ stub_request(:get, url)
+ .to_raise(SocketError)
+ expect { subject.logged_in? }
+ .to raise_error(VagrantPlugins::LoginCommand::Errors::ServerUnreachable)
+ end
end
end
@@ -89,11 +99,29 @@ describe VagrantPlugins::LoginCommand::Client do
end
end
- describe "#token, #store_token, #clear_token" do
- it "returns nil if there is no token" do
- expect(subject.token).to be_nil
+ describe "#token" do
+ it "reads ATLAS_TOKEN" do
+ stub_env("ATLAS_TOKEN", "ABCD1234")
+ expect(subject.token).to eq("ABCD1234")
end
+ it "reads the stored file" do
+ subject.store_token("EFGH5678")
+ expect(subject.token).to eq("EFGH5678")
+ end
+
+ it "prefers the environment variable" do
+ stub_env("ATLAS_TOKEN", "ABCD1234")
+ subject.store_token("EFGH5678")
+ expect(subject.token).to eq("ABCD1234")
+ end
+
+ it "returns nil if there's no token set" do
+ expect(subject.token).to be(nil)
+ end
+ end
+
+ describe "#store_token, #clear_token" do
it "stores the token and can re-access it" do
subject.store_token("foo")
expect(subject.token).to eq("foo")
From 0506e177786408dbc6e5e55090a935e53a7a9c0a Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Wed, 10 Dec 2014 15:11:04 -0800
Subject: [PATCH 109/203] Update Atlas Push to use new vagrant-login API
---
plugins/pushes/atlas/config.rb | 2 +-
test/unit/plugins/pushes/atlas/config_test.rb | 32 +------------------
2 files changed, 2 insertions(+), 32 deletions(-)
diff --git a/plugins/pushes/atlas/config.rb b/plugins/pushes/atlas/config.rb
index d4d2da2c5..55543fae6 100644
--- a/plugins/pushes/atlas/config.rb
+++ b/plugins/pushes/atlas/config.rb
@@ -85,7 +85,7 @@ module VagrantPlugins
errors = _detected_errors
if missing?(@token)
- token = token_from_vagrant_login(machine.env) || ENV["ATLAS_TOKEN"]
+ token = token_from_vagrant_login(machine.env)
if missing?(token)
errors << I18n.t("atlas_push.errors.missing_token")
else
diff --git a/test/unit/plugins/pushes/atlas/config_test.rb b/test/unit/plugins/pushes/atlas/config_test.rb
index 1b2695ba9..580a39ab0 100644
--- a/test/unit/plugins/pushes/atlas/config_test.rb
+++ b/test/unit/plugins/pushes/atlas/config_test.rb
@@ -73,13 +73,9 @@ describe VagrantPlugins::AtlasPush::Config do
before do
allow(subject).to receive(:token_from_vagrant_login)
.and_return("token_from_vagrant_login")
-
- allow(ENV).to receive(:[]).and_call_original
- allow(ENV).to receive(:[])
- .with("ATLAS_TOKEN").and_return("token_from_env")
end
- it "uses the token in the Vagrantfile" do
+ it "uses the token from vagrant-login" do
subject.token = ""
subject.finalize!
expect(errors).to be_empty
@@ -87,32 +83,10 @@ describe VagrantPlugins::AtlasPush::Config do
end
end
- context "when ATLAS_TOKEN is set in the environment" do
- before do
- allow(subject).to receive(:token_from_vagrant_login)
- .and_return(nil)
-
- allow(ENV).to receive(:[]).and_call_original
- allow(ENV).to receive(:[])
- .with("ATLAS_TOKEN").and_return("token_from_env")
- end
-
- it "uses the token in the environment" do
- subject.token = ""
- subject.finalize!
- expect(errors).to be_empty
- expect(subject.token).to eq("token_from_env")
- end
- end
-
context "when a token is given in the Vagrantfile" do
before do
allow(subject).to receive(:token_from_vagrant_login)
.and_return("token_from_vagrant_login")
-
- allow(ENV).to receive(:[]).and_call_original
- allow(ENV).to receive(:[])
- .with("ATLAS_TOKEN").and_return("token_from_env")
end
it "uses the token in the Vagrantfile" do
@@ -127,10 +101,6 @@ describe VagrantPlugins::AtlasPush::Config do
before do
allow(subject).to receive(:token_from_vagrant_login)
.and_return(nil)
-
- allow(ENV).to receive(:[]).and_call_original
- allow(ENV).to receive(:[])
- .with("ATLAS_TOKEN").and_return(nil)
end
it "returns an error" do
From 9a575a79ec45db1fe93816a823294170999fc659 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 11 Dec 2014 01:21:46 -0800
Subject: [PATCH 110/203] Use the new Rails error format
---
plugins/commands/login/client.rb | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/plugins/commands/login/client.rb b/plugins/commands/login/client.rb
index f06772be9..0e28bc374 100644
--- a/plugins/commands/login/client.rb
+++ b/plugins/commands/login/client.rb
@@ -75,10 +75,7 @@ module VagrantPlugins
false
rescue RestClient::NotAcceptable => e
begin
- errors = JSON.parse(e.response)["errors"]
- .map { |h| h["message"] }
- .join("\n")
-
+ errors = JSON.parse(e.response)["errors"].join("\n")
raise Errors::ServerError, errors: errors
rescue JSON::ParserError; end
From 4d576ebf79028cf5b887abeb02d63822c16be559 Mon Sep 17 00:00:00 2001
From: Jacob Clark
Date: Thu, 11 Dec 2014 14:46:35 +0000
Subject: [PATCH 111/203] Vagrantfile is case sensitive on strict file sys
---
website/docs/source/v2/vagrantfile/index.html.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/website/docs/source/v2/vagrantfile/index.html.md b/website/docs/source/v2/vagrantfile/index.html.md
index 66de9b7a1..a83b98620 100644
--- a/website/docs/source/v2/vagrantfile/index.html.md
+++ b/website/docs/source/v2/vagrantfile/index.html.md
@@ -9,7 +9,7 @@ The primary function of the Vagrantfile is to describe the type
of machine required for a project, and how to configure and
provision these machines. Vagrantfiles are called Vagrantfiles because
the actual literal filename for the file is `Vagrantfile` (casing doesn't
-matter).
+matter unless your file system is running in a strict case sensitive mode).
Vagrant is meant to run with one Vagrantfile per project, and the Vagrantfile
is supposed to be committed to version control. This allows other developers
From 1c328914f82365e8fa81e7813b0daf5c9f73ee9b Mon Sep 17 00:00:00 2001
From: Jack Pearkes
Date: Thu, 11 Dec 2014 10:17:38 -0800
Subject: [PATCH 112/203] docs: link to the atlas box search page instead of
homepage
---
website/docs/source/v2/boxes.html.md | 4 ++--
website/docs/source/v2/cli/box.html.md | 4 ++--
website/docs/source/v2/cli/login.html.md | 2 +-
website/docs/source/v2/getting-started/boxes.html.md | 4 ++--
website/docs/source/v2/hyperv/usage.html.md | 2 +-
5 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/website/docs/source/v2/boxes.html.md b/website/docs/source/v2/boxes.html.md
index 491a5a631..e123b6c2d 100644
--- a/website/docs/source/v2/boxes.html.md
+++ b/website/docs/source/v2/boxes.html.md
@@ -14,7 +14,7 @@ boxes. You can read the documentation on the [vagrant box](/v2/cli/box.html)
command for more information.
The easiest way to use a box is to add a box from the
-[publicly available catalog of Vagrant boxes](https://atlas.hashicorp.com).
+[publicly available catalog of Vagrant boxes](https://atlas.hashicorp.com/boxes/search).
You can also add and share your own customized boxes on this website.
Boxes also support versioning so that members of your team using Vagrant
@@ -27,7 +27,7 @@ sub-pages in the navigation to the left.
## Discovering Boxes
The easiest way to find boxes is to look on the
-[public Vagrant box catalog](https://atlas.hashicorp.com)
+[public Vagrant box catalog](https://atlas.hashicorp.com/boxes/search)
for a box matching your use case. The catalog contains most major operating
systems as bases, as well as specialized boxes to get you up and running
quickly with LAMP stacks, Ruby, Python, etc.
diff --git a/website/docs/source/v2/cli/box.html.md b/website/docs/source/v2/cli/box.html.md
index e3b39b4cb..910f07d98 100644
--- a/website/docs/source/v2/cli/box.html.md
+++ b/website/docs/source/v2/cli/box.html.md
@@ -26,10 +26,10 @@ This adds a box with the given address to Vagrant. The address can be
one of three things:
* A shorthand name from the
-[public catalog of available Vagrant images](https://atlas.hashicorp.com),
+[public catalog of available Vagrant images](https://atlas.hashicorp.com/boxes/search),
such as "hashicorp/precise64".
-* File path or HTTP URL to a box in a [catalog](https://atlas.hashicorp.com).
+* File path or HTTP URL to a box in a [catalog](https://atlas.hashicorp.com/boxes/search).
For HTTP, basic authentication is supported and `http_proxy` environmental
variables are respected. HTTPS is also supported.
diff --git a/website/docs/source/v2/cli/login.html.md b/website/docs/source/v2/cli/login.html.md
index a984cc77d..c8f6ee7d9 100644
--- a/website/docs/source/v2/cli/login.html.md
+++ b/website/docs/source/v2/cli/login.html.md
@@ -7,7 +7,7 @@ sidebar_current: "cli-login"
**Command: `vagrant login`**
-The login command is used to authenticate with a
+The login command is used to authenticate with the
[HashiCorp's Atlas](https://atlas.hashicorp.com) server. Logging is only
necessary if you're accessing protected boxes or using
[Vagrant Share](/v2/share/index.html).
diff --git a/website/docs/source/v2/getting-started/boxes.html.md b/website/docs/source/v2/getting-started/boxes.html.md
index 6a64f8a71..7ed1f83d7 100644
--- a/website/docs/source/v2/getting-started/boxes.html.md
+++ b/website/docs/source/v2/getting-started/boxes.html.md
@@ -27,7 +27,7 @@ $ vagrant box add hashicorp/precise32
```
This will download the box named "hashicorp/precise32" from
-[HashiCorp's Atlas](https://atlas.hashicorp.com), a place where you can find
+[HashiCorp's Atlas box catalog](https://atlas.hashicorp.com/boxes/search), a place where you can find
and host boxes. While it is easiest to download boxes from HashiCorp's Atlas
you can also add boxes from a local file, custom URL, etc.
@@ -64,7 +64,7 @@ For the remainder of this getting started guide, we'll only use the
this getting started guide, the first question you'll probably have is
"where do I find more boxes?"
-The best place to find more boxes is [HashiCorp's Atlas](https://atlas.hashicorp.com).
+The best place to find more boxes is [HashiCorp's Atlas box catalog](https://atlas.hashicorp.com/boxes/search).
HashiCorp's Atlas has a public directory of freely available boxes that
run various platforms and technologies. HashiCorp's Atlas also has a great search
feature to allow you to find the box you care about.
diff --git a/website/docs/source/v2/hyperv/usage.html.md b/website/docs/source/v2/hyperv/usage.html.md
index e91c7e92e..5751fa511 100644
--- a/website/docs/source/v2/hyperv/usage.html.md
+++ b/website/docs/source/v2/hyperv/usage.html.md
@@ -17,5 +17,5 @@ admin rights. Vagrant will show you an error if it doesn't have the proper
permissions.
Boxes for Hyper-V can be easily found on
-[HashiCorp's Atlas](https://atlas.hashicorp.com). To get started, you might
+[HashiCorp's Atlas](https://atlas.hashicorp.com/boxes/search). To get started, you might
want to try the `hashicorp/precise64` box.
From 68d82349ddb2ca67ce09439241d38c6d5f5544c4 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 11 Dec 2014 11:15:24 -0800
Subject: [PATCH 113/203] Fix failing test
---
test/unit/plugins/pushes/ftp/push_test.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/unit/plugins/pushes/ftp/push_test.rb b/test/unit/plugins/pushes/ftp/push_test.rb
index ca8ee2752..5b5ec7c10 100644
--- a/test/unit/plugins/pushes/ftp/push_test.rb
+++ b/test/unit/plugins/pushes/ftp/push_test.rb
@@ -9,7 +9,7 @@ describe VagrantPlugins::FTPPush::Push do
let(:env) { isolated_environment }
let(:config) do
double("config",
- host: "127.0.0.1:21212",
+ host: "127.0.0.1:51234",
username: "sethvargo",
password: "bacon",
passive: false,
@@ -22,7 +22,7 @@ describe VagrantPlugins::FTPPush::Push do
describe "#push" do
before(:all) do
- @server = FakeFtp::Server.new(21212, 21213)
+ @server = FakeFtp::Server.new(51234, 21213)
@server.start
@dir = Dir.mktmpdir
From 6cae92a200b1d231056bbe3c4aae79bc7743838a Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 11 Dec 2014 16:47:50 -0800
Subject: [PATCH 114/203] Cleanup generated Vagrantfile
---
templates/commands/init/Vagrantfile.erb | 143 +++---------------------
1 file changed, 13 insertions(+), 130 deletions(-)
diff --git a/templates/commands/init/Vagrantfile.erb b/templates/commands/init/Vagrantfile.erb
index 710e61664..c3f32fc00 100644
--- a/templates/commands/init/Vagrantfile.erb
+++ b/templates/commands/init/Vagrantfile.erb
@@ -8,9 +8,10 @@
Vagrant.configure(2) do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
- # vagrantup.com
+ # https://docs.vagrantup.com.
- # Every Vagrant virtual environment requires a box to build off of.
+ # Every Vagrant development environment requires a box. You can search for
+ # boxes at https://atlas.hashicorp.com/search.
config.vm.box = "<%= box_name %>"
<% if box_url -%>
@@ -38,10 +39,6 @@ Vagrant.configure(2) do |config|
# your network.
# config.vm.network "public_network"
- # If true, then any SSH connections made will enable agent forwarding.
- # Default value: false
- # config.ssh.forward_agent = true
-
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
@@ -53,134 +50,20 @@ Vagrant.configure(2) do |config|
# Example for VirtualBox:
#
# config.vm.provider "virtualbox" do |vb|
- # # Don't boot with headless mode
+ # # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
- # # Use VBoxManage to customize the VM. For example to change memory:
- # vb.customize ["modifyvm", :id, "--memory", "1024"]
+ # # Customize the amount of memory on the VM:
+ # vb.memory = "1024"
# end
#
- # View the documentation for the provider you're using for more
+ # View the documentation for the provider you are using for more
# information on available options.
- # Enable provisioning with CFEngine. CFEngine Community packages are
- # automatically installed. For example, configure the host as a
- # policy server and optionally a policy file to run:
- #
- # config.vm.provision "cfengine" do |cf|
- # cf.am_policy_hub = true
- # # cf.run_file = "motd.cf"
- # end
- #
- # You can also configure and bootstrap a client to an existing
- # policy server:
- #
- # config.vm.provision "cfengine" do |cf|
- # cf.policy_server_address = "10.0.2.15"
- # end
-
- # Enable provisioning with Puppet stand alone. Puppet manifests
- # are contained in a directory path relative to this Vagrantfile.
- # You will need to create the manifests directory and a manifest in
- # the file default.pp in the manifests_path directory.
- #
- # config.vm.provision "puppet" do |puppet|
- # puppet.manifests_path = "manifests"
- # puppet.manifest_file = "default.pp"
- # end
-
- # Enable provisioning with Chef Solo, specifying a cookbooks path, roles
- # path, and data_bags path (all relative to this Vagrantfile), and adding
- # some recipes and/or roles.
- #
- # config.vm.provision "chef_solo" do |chef|
- # chef.cookbooks_path = "~/chef/cookbooks"
- # chef.roles_path = "~/chef/roles"
- # chef.data_bags_path = "~/chef/data_bags"
- #
- # chef.add_recipe "mysql"
- # chef.add_role "web"
- #
- # chef.json = { mysql_password: "foo" }
- # end
- #
- # Chef Solo will automatically install the latest version of Chef for you.
- # This can be configured in the provisioner block:
- #
- # config.vm.provision "chef_solo" do |chef|
- # chef.version = "11.16.4"
- # end
- #
- # Alternative you can disable the installation of Chef entirely:
- #
- # config.vm.provision "chef_solo" do |chef|
- # chef.install = false
- # end
-
- # Enable provisioning with Chef Zero. The Chef Zero provisioner accepts the
- # exact same parameter as the Chef Solo provisioner:
- #
- # config.vm.provision "chef_zero" do |chef|
- # chef.cookbooks_path = "~/chef/cookbooks"
- # chef.roles_path = "~/chef/roles"
- # chef.data_bags_path = "~/chef/data_bags"
- #
- # chef.add_recipe "mysql"
- # chef.add_role "web"
- #
- # # You may also specify custom JSON attributes:
- # chef.json = { mysql_password: "foo" }
- # end
-
- # Enable provisioning with Chef Server, specifying the chef server URL,
- # and the path to the validation key (relative to this Vagrantfile).
- #
- # The Hosted Chef platform uses HTTPS. Substitute your organization for
- # ORGNAME in the URL and validation key.
- #
- # If you have your own Chef Server, use the appropriate URL, which may be
- # HTTP instead of HTTPS depending on your configuration. Also change the
- # validation key to validation.pem.
- #
- # config.vm.provision "chef_client" do |chef|
- # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
- # chef.validation_key_path = "ORGNAME-validator.pem"
- # end
- #
- # If you're using the Hosted Chef platform, your validator client is
- # ORGNAME-validator, replacing ORGNAME with your organization name.
- #
- # If you have your own Chef Server, the default validation client name is
- # chef-validator, unless you changed the configuration.
- #
- # chef.validation_client_name = "ORGNAME-validator"
- #
- # Chef Client will automatically install the latest version of Chef for you.
- # This can be configured in the provisioner block:
- #
- # config.vm.provision "chef_client" do |chef|
- # chef.version = "11.16.4"
- # end
- #
- # Alternative you can disable the installation of Chef entirely:
- #
- # config.vm.provision "chef_client" do |chef|
- # chef.install = false
- # end
-
- # Enable provisioning with Chef Apply, specifying an inline recipe to execute
- # on the target system.
- #
- # config.vm.provision "chef_apply" do |chef|
- # chef.recipe = <<-RECIPE
- # package "curl"
- # RECIPE
- # end
- #
- # Chef Apply will automatically install the latest version of Chef for you.
- # This can be configured in the provisioner block:
- #
- # config.vm.provision "chef_apply" do |chef|
- # chef.version = "11.16.4"
- # end
+ # Enable provisioning with a shell script. Additional provisioners such as
+ # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
+ # documentation for more information about their specific syntax and use.
+ # config.vm.provision "shell", inline <<-SHELL
+ # sudo apt-get install apache2
+ # SHELL
end
From 0dcdc2312ba3b6a5270467602bdd6dc8361741fc Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 11 Dec 2014 16:48:20 -0800
Subject: [PATCH 115/203] Remove editor comments from min Vagrantfile
---
templates/commands/init/Vagrantfile.min.erb | 3 ---
1 file changed, 3 deletions(-)
diff --git a/templates/commands/init/Vagrantfile.min.erb b/templates/commands/init/Vagrantfile.min.erb
index 6120ce0e4..ac70f5e7c 100644
--- a/templates/commands/init/Vagrantfile.min.erb
+++ b/templates/commands/init/Vagrantfile.min.erb
@@ -1,6 +1,3 @@
-# -*- mode: ruby -*-
-# vi: set ft=ruby :
-
Vagrant.configure(2) do |config|
config.vm.box = "<%= box_name %>"
<% if box_url -%>
From b590ee2b3a3f96da042d28d7df20b4296f73e628 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 11 Dec 2014 16:50:56 -0800
Subject: [PATCH 116/203] Add push example
---
templates/commands/init/Vagrantfile.erb | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/templates/commands/init/Vagrantfile.erb b/templates/commands/init/Vagrantfile.erb
index c3f32fc00..4fbb647c8 100644
--- a/templates/commands/init/Vagrantfile.erb
+++ b/templates/commands/init/Vagrantfile.erb
@@ -60,6 +60,13 @@ Vagrant.configure(2) do |config|
# View the documentation for the provider you are using for more
# information on available options.
+ # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies
+ # such as FTP and Heroku are also available. See the documentation at
+ # https://docs.vagrantup.com/v2/push/atlas.html for more information.
+ # config.push.define "atlas" do |push|
+ # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME"
+ # end
+
# Enable provisioning with a shell script. Additional provisioners such as
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
# documentation for more information about their specific syntax and use.
From b6deb6bc286accd73b8bb08b90fe7be05adec458 Mon Sep 17 00:00:00 2001
From: Joel Handwell
Date: Thu, 11 Dec 2014 20:08:33 -0500
Subject: [PATCH 117/203] added chec_zero page to be shown in sidebar
---
website/docs/source/layouts/layout.erb | 1 +
1 file changed, 1 insertion(+)
diff --git a/website/docs/source/layouts/layout.erb b/website/docs/source/layouts/layout.erb
index 8a1883920..310d7b0a8 100644
--- a/website/docs/source/layouts/layout.erb
+++ b/website/docs/source/layouts/layout.erb
@@ -173,6 +173,7 @@
>Ansible
>CFEngine
>Chef Solo
+ >Chef Zero
>Chef Client
>Chef Apply
>Docker
From 90a12ee476cb26e5bdc91d9f11640e5ab6a431c7 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 11 Dec 2014 17:22:05 -0800
Subject: [PATCH 118/203] Update CHANGELOG
---
CHANGELOG.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 18b79cc43..864eac776 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 1.7.1 (December 11, 2014)
+
+IMPROVEMENTS:
+
+ - provisioners/ansible: Use Docker proxy if needed. [GH-4906]
+
## 1.7.0 (December 9, 2014)
BREAKING CHANGES:
From a3abdadc1c809ecc045b348bffbd772ff23a7eef Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 11 Dec 2014 17:24:54 -0800
Subject: [PATCH 119/203] Update CHANGELOG
---
CHANGELOG.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 864eac776..3340fd82d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@ IMPROVEMENTS:
- provisioners/ansible: Use Docker proxy if needed. [GH-4906]
+BUG FIXES:
+
+ - providers/docker: Add support of SSH agent forwarding. [GH-4905]
+
## 1.7.0 (December 9, 2014)
BREAKING CHANGES:
@@ -99,7 +103,6 @@ BUG FIXES:
- providers/docker: Fix issue where multiple identical proxy VMs would
be created. [GH-3963]
- providers/docker: Multiple links with the same name work. [GH-4571]
- - providers/docker: Add support of SSH agent forwarding. [GH-4905]
- providers/virtualbox: Show a human-friendly error if VirtualBox didn't
clean up an existing VM. [GH-4681]
- providers/virtualbox: Detect case when VirtualBox reports 0.0.0.0 as
From 1f98237386e23724b8ecd1dff14aed8657244d62 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 11 Dec 2014 17:34:51 -0800
Subject: [PATCH 120/203] v1.7.1
---
version.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/version.txt b/version.txt
index bd8bf882d..943f9cbc4 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-1.7.0
+1.7.1
From fa7131ff6e8f4107be94777fb5caf73521422965 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Fri, 12 Dec 2014 00:49:42 -0800
Subject: [PATCH 121/203] website/www: fix Vagrantfile
---
website/www/Vagrantfile | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/website/www/Vagrantfile b/website/www/Vagrantfile
index 7ce24fe70..2d8d8c9b4 100644
--- a/website/www/Vagrantfile
+++ b/website/www/Vagrantfile
@@ -4,13 +4,11 @@
$script = <