Ray Ruvinskiy 5a7e00c5b1 Add HTTPS download options to box update and box outdated
Vagrant::Box.load_metadata did not provide a way to specify the HTTPS
download options that could be specified when downloading boxes
(ca cert, ca path, client cert, insecure). As a result, while it was
possible to add a box whose metadata file needed to be downloaded with one of
those options specified, it was impossible to check for updates. The following
changes have been made to address the situation:

1. Create a DownloadMixins module to provide the --insecure, --cacert, --capth,
   and --cert command line options to all of `vagrant box add`,
   `vagrant box update`, and `vagrant box outdated`.
2. Extend `Vagrant::Box.has_update?` and `Vagrant::Box.load_metadata` to accept
   said download options.
3. Extend `box outdated` and `box update` commands to pass download options
   down.
4. Extend `Vagrant::Builtin::Action::BoxCheckOutdated` to honour download
   options.
5. Options specified on the command line take precedence over options specified
   in the machine configuration, if any.
6. Fix bug in `vagrant box add` where client cert was being passed down using
   the wrong environment key.
7. Unit test coverage in update_test and box_check_outdated_test.

Resolves #4420
2014-09-07 23:57:34 -04:00

358 lines
10 KiB
Ruby

require "pathname"
require "tmpdir"
require File.expand_path("../../../../../base", __FILE__)
require Vagrant.source_root.join("plugins/commands/box/command/update")
describe VagrantPlugins::CommandBox::Command::Update do
include_context "unit"
let(:argv) { [] }
let(:iso_env) do
# We have to create a Vagrantfile so there is a root path
test_iso_env.vagrantfile("")
test_iso_env.create_vagrant_env
end
let(:test_iso_env) { isolated_environment }
let(:action_runner) { double("action_runner") }
let(:machine) { iso_env.machine(iso_env.machine_names[0], :dummy) }
let(:download_options) { ["--insecure",
"--cacert", "foo",
"--capath", "bar",
"--cert", "baz"] }
subject { described_class.new(argv, iso_env) }
before do
iso_env.stub(action_runner: action_runner)
machine.config.vm.box = "foo"
end
describe "execute" do
context "updating specific box" do
let(:argv) { ["--box", "foo"] }
let(:metadata_url) { Pathname.new(Dir.mktmpdir).join("metadata.json") }
before do
metadata_url.open("w") do |f|
f.write("")
end
test_iso_env.box3(
"foo", "1.0", :virtualbox, metadata_url: metadata_url.to_s)
end
it "doesn't update if they're up to date" do
called = false
allow(action_runner).to receive(:run) do |callable, opts|
if opts[:box_provider]
called = true
end
opts
end
subject.execute
expect(called).to be_false
end
it "does update if there is an update" do
metadata_url.open("w") do |f|
f.write(<<-RAW)
{
"name": "foo",
"versions": [
{
"version": "1.0"
},
{
"version": "1.1",
"providers": [
{
"name": "virtualbox",
"url": "bar"
}
]
}
]
}
RAW
end
action_called = false
allow(action_runner).to receive(:run) do |action, opts|
if opts[:box_provider]
action_called = true
expect(opts[:box_url]).to eq(metadata_url.to_s)
expect(opts[:box_provider]).to eq("virtualbox")
expect(opts[:box_version]).to eq("1.1")
expect(opts[:box_download_ca_path]).to be_nil
expect(opts[:box_download_ca_cert]).to be_nil
expect(opts[:box_client_cert]).to be_nil
expect(opts[:box_download_insecure]).to be_nil
end
opts
end
subject.execute
expect(action_called).to be_true
end
it "raises an error if there are multiple providers" do
test_iso_env.box3("foo", "1.0", :vmware)
expect(action_runner).to receive(:run).never
expect { subject.execute }.
to raise_error(Vagrant::Errors::BoxUpdateMultiProvider)
end
context "with multiple providers and specifying the provider" do
let(:argv) { ["--box", "foo", "--provider", "vmware"] }
it "updates the proper box" do
metadata_url.open("w") do |f|
f.write(<<-RAW)
{
"name": "foo",
"versions": [
{
"version": "1.0"
},
{
"version": "1.1",
"providers": [
{
"name": "vmware",
"url": "bar"
}
]
}
]
}
RAW
end
test_iso_env.box3("foo", "1.0", :vmware)
action_called = false
allow(action_runner).to receive(:run) do |action, opts|
if opts[:box_provider]
action_called = true
expect(opts[:box_url]).to eq(metadata_url.to_s)
expect(opts[:box_provider]).to eq("vmware")
expect(opts[:box_version]).to eq("1.1")
end
opts
end
subject.execute
expect(action_called).to be_true
end
it "raises an error if that provider doesn't exist" do
expect(action_runner).to receive(:run).never
expect { subject.execute }.
to raise_error(Vagrant::Errors::BoxNotFoundWithProvider)
end
end
context "download options are specified" do
let(:argv) { ["--box", "foo" ].concat(download_options) }
it "passes down download options" do
metadata_url.open("w") do |f|
f.write(<<-RAW)
{
"name": "foo",
"versions": [
{
"version": "1.0"
},
{
"version": "1.1",
"providers": [
{
"name": "virtualbox",
"url": "bar"
}
]
}
]
}
RAW
end
action_called = false
allow(action_runner).to receive(:run) do |action, opts|
if opts[:box_provider]
action_called = true
expect(opts[:box_download_ca_cert]).to eq("foo")
expect(opts[:box_download_ca_path]).to eq("bar")
expect(opts[:box_client_cert]).to eq("baz")
expect(opts[:box_download_insecure]).to be_true
end
opts
end
subject.execute
expect(action_called).to be_true
end
end
context "with a box that doesn't exist" do
let(:argv) { ["--box", "nope"] }
it "raises an exception" do
expect(action_runner).to receive(:run).never
expect { subject.execute }.
to raise_error(Vagrant::Errors::BoxNotFound)
end
end
end
context "updating environment machines" do
before do
allow(subject).to receive(:with_target_vms) { |&block| block.call machine }
end
let(:box) do
box_dir = test_iso_env.box3("foo", "1.0", :virtualbox)
box = Vagrant::Box.new(
"foo", :virtualbox, "1.0", box_dir, metadata_url: "foo")
box.stub(has_update?: nil)
box
end
it "ignores machines without boxes" do
expect(action_runner).to receive(:run).never
subject.execute
end
it "doesn't update boxes if they're up-to-date" do
machine.stub(box: box)
expect(box).to receive(:has_update?).
with(machine.config.vm.box_version,
{download_options:
{ca_cert: nil, ca_path: nil, client_cert: nil,
insecure: false}}).
and_return(nil)
expect(action_runner).to receive(:run).never
subject.execute
end
context "boxes have an update" do
let(:md) {
md = Vagrant::BoxMetadata.new(StringIO.new(<<-RAW))
{
"name": "foo",
"versions": [
{
"version": "1.0"
},
{
"version": "1.1",
"providers": [
{
"name": "virtualbox",
"url": "bar"
}
]
}
]
}
RAW
}
before { machine.stub(box: box) }
it "updates boxes" do
expect(box).to receive(:has_update?).
with(machine.config.vm.box_version,
{download_options:
{ca_cert: nil, ca_path: nil, client_cert: nil,
insecure: false}}).
and_return([md, md.version("1.1"), md.version("1.1").provider("virtualbox")])
expect(action_runner).to receive(:run).with { |action, opts|
expect(opts[:box_url]).to eq(box.metadata_url)
expect(opts[:box_provider]).to eq("virtualbox")
expect(opts[:box_version]).to eq("1.1")
expect(opts[:ui]).to equal(machine.ui)
true
}
subject.execute
end
context "machine has download options" do
before do
machine.config.vm.box_download_ca_cert = "oof"
machine.config.vm.box_download_ca_path = "rab"
machine.config.vm.box_download_client_cert = "zab"
machine.config.vm.box_download_insecure = false
end
it "uses download options from machine" do
expect(box).to receive(:has_update?).
with(machine.config.vm.box_version,
{download_options:
{ca_cert: "oof", ca_path: "rab", client_cert: "zab",
insecure: false}}).
and_return([md, md.version("1.1"), md.version("1.1").provider("virtualbox")])
expect(action_runner).to receive(:run).with { |action, opts|
expect(opts[:box_download_ca_cert]).to eq("oof")
expect(opts[:box_download_ca_path]).to eq("rab")
expect(opts[:box_client_cert]).to eq("zab")
expect(opts[:box_download_insecure]).to be_false
true
}
subject.execute
end
context "download options are specified on the command line" do
let(:argv) { download_options }
it "overrides download options from machine with options from CLI" do
expect(box).to receive(:has_update?).
with(machine.config.vm.box_version,
{download_options:
{ca_cert: "foo", ca_path: "bar", client_cert: "baz",
insecure: true}}).
and_return([md, md.version("1.1"),
md.version("1.1").provider("virtualbox")])
expect(action_runner).to receive(:run).with { |action, opts|
expect(opts[:box_download_ca_cert]).to eq("foo")
expect(opts[:box_download_ca_path]).to eq("bar")
expect(opts[:box_client_cert]).to eq("baz")
expect(opts[:box_download_insecure]).to be_true
true
}
subject.execute
end
end
end
end
end
end
end