core: BoxCheckOutdated can check if a box is outdated
This commit is contained in:
parent
f2509f5c65
commit
e537e02d9d
|
@ -9,6 +9,7 @@ module Vagrant
|
||||||
# and are thus available to all plugins as a "standard library" of sorts.
|
# and are thus available to all plugins as a "standard library" of sorts.
|
||||||
module Builtin
|
module Builtin
|
||||||
autoload :BoxAdd, "vagrant/action/builtin/box_add"
|
autoload :BoxAdd, "vagrant/action/builtin/box_add"
|
||||||
|
autoload :BoxCheckOutdated, "vagrant/action/builtin/box_check_outdated"
|
||||||
autoload :BoxRemove, "vagrant/action/builtin/box_remove"
|
autoload :BoxRemove, "vagrant/action/builtin/box_remove"
|
||||||
autoload :Call, "vagrant/action/builtin/call"
|
autoload :Call, "vagrant/action/builtin/call"
|
||||||
autoload :Confirm, "vagrant/action/builtin/confirm"
|
autoload :Confirm, "vagrant/action/builtin/confirm"
|
||||||
|
@ -45,6 +46,14 @@ module Vagrant
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This actions checks if a box is outdated in a given Vagrant
|
||||||
|
# environment for a single machine.
|
||||||
|
def self.action_box_outdated
|
||||||
|
Builder.new.tap do |b|
|
||||||
|
b.use Builtin::BoxCheckOutdated
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# This is the action that will remove a box given a name (and optionally
|
# This is the action that will remove a box given a name (and optionally
|
||||||
# a provider). This middleware sequence is built-in to Vagrant. Plugins
|
# a provider). This middleware sequence is built-in to Vagrant. Plugins
|
||||||
# can hook into this like any other middleware sequence.
|
# can hook into this like any other middleware sequence.
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
require "digest/sha1"
|
||||||
|
require "log4r"
|
||||||
|
require "pathname"
|
||||||
|
require "uri"
|
||||||
|
|
||||||
|
require "vagrant/box_metadata"
|
||||||
|
require "vagrant/util/downloader"
|
||||||
|
require "vagrant/util/file_checksum"
|
||||||
|
require "vagrant/util/platform"
|
||||||
|
|
||||||
|
module Vagrant
|
||||||
|
module Action
|
||||||
|
module Builtin
|
||||||
|
# This middleware checks if there are outdated boxes. By default,
|
||||||
|
# it only checks locally, but if `box_outdated_refresh` is set, it
|
||||||
|
# will refresh the metadata associated with a box.
|
||||||
|
class BoxCheckOutdated
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
@logger = Log4r::Logger.new(
|
||||||
|
"vagrant::action::builtin::box_check_outdated")
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
machine = env[:machine]
|
||||||
|
|
||||||
|
if !machine.box
|
||||||
|
# The box doesn't exist. I suppose technically that means
|
||||||
|
# that it is "outdated" but we show a specialized error
|
||||||
|
# message anyways.
|
||||||
|
raise Errors::BoxOutdatedNoBox, name: machine.config.vm.box
|
||||||
|
end
|
||||||
|
|
||||||
|
if !machine.box.metadata_url
|
||||||
|
# This box doesn't have a metadata URL, so we can't
|
||||||
|
# possibly check the version information.
|
||||||
|
raise Errors::BoxOutdatedNoMetadata, name: machine.box.name
|
||||||
|
end
|
||||||
|
|
||||||
|
md = machine.box.load_metadata
|
||||||
|
newer = md.version(
|
||||||
|
"> #{machine.box.version}", provider: machine.box.provider)
|
||||||
|
if !newer
|
||||||
|
env[:ui].success(I18n.t(
|
||||||
|
"vagrant.box_up_to_date_single",
|
||||||
|
name: machine.box.name,
|
||||||
|
version: machine.box.version))
|
||||||
|
|
||||||
|
env[:box_outdated] = false
|
||||||
|
return @app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
env[:ui].warn(I18n.t(
|
||||||
|
"vagrant.box_outdated_single",
|
||||||
|
name: machine.box.name,
|
||||||
|
current: machine.box.version,
|
||||||
|
latest: newer.version))
|
||||||
|
env[:box_outdated] = true
|
||||||
|
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -172,6 +172,14 @@ module Vagrant
|
||||||
error_key(:box_metadata_malformed)
|
error_key(:box_metadata_malformed)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class BoxOutdatedNoBox < VagrantError
|
||||||
|
error_key(:box_outdated_no_box)
|
||||||
|
end
|
||||||
|
|
||||||
|
class BoxOutdatedNoMetadata < VagrantError
|
||||||
|
error_key(:box_outdated_no_metadata)
|
||||||
|
end
|
||||||
|
|
||||||
class BoxProviderDoesntMatch < VagrantError
|
class BoxProviderDoesntMatch < VagrantError
|
||||||
error_key(:box_provider_doesnt_match)
|
error_key(:box_provider_doesnt_match)
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,10 +5,34 @@ module VagrantPlugins
|
||||||
module Command
|
module Command
|
||||||
class Outdated < Vagrant.plugin("2", :command)
|
class Outdated < Vagrant.plugin("2", :command)
|
||||||
def execute
|
def execute
|
||||||
OptionParser.new do |o|
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
o.banner = "Usage: vagrant box outdated"
|
o.banner = "Usage: vagrant box outdated"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("--global", "Check all boxes installed.") do |g|
|
||||||
|
options[:global] = g
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
argv = parse_options(opts)
|
||||||
|
|
||||||
|
# If we're checking the boxes globally, then do that.
|
||||||
|
if options[:global]
|
||||||
|
outdated_global
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
with_target_vms(argv) do |machine|
|
||||||
|
@env.action_runner.run(Vagrant::Action.action_box_outdated, {
|
||||||
|
box_outdated_refresh: true,
|
||||||
|
machine: machine,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def outdated_global
|
||||||
boxes = {}
|
boxes = {}
|
||||||
@env.boxes.all.reverse.each do |name, version, provider|
|
@env.boxes.all.reverse.each do |name, version, provider|
|
||||||
next if boxes[name]
|
next if boxes[name]
|
||||||
|
@ -49,9 +73,6 @@ module VagrantPlugins
|
||||||
latest: latest.to_s,))
|
latest: latest.to_s,))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Success, exit status 0
|
|
||||||
0
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,12 +30,18 @@ en:
|
||||||
Loading metadata for box '%{name}'
|
Loading metadata for box '%{name}'
|
||||||
box_outdated: |-
|
box_outdated: |-
|
||||||
* '%{name}' is outdated! Current: %{current}. Latest: %{latest}
|
* '%{name}' is outdated! Current: %{current}. Latest: %{latest}
|
||||||
|
box_outdated_single: |-
|
||||||
|
A newer version of the box '%{name}' is available! You currently
|
||||||
|
have version '%{current}'. The latest is version '%{latest}'. Run
|
||||||
|
`vagrant box update` to update.
|
||||||
box_outdated_metadata_error: |-
|
box_outdated_metadata_error: |-
|
||||||
* '%{name}': Error loading metadata: %{message}
|
* '%{name}': Error loading metadata: %{message}
|
||||||
box_outdated_no_metadata: |-
|
box_outdated_no_metadata: |-
|
||||||
* '%{name}' wasn't added from a catalog, no version information
|
* '%{name}' wasn't added from a catalog, no version information
|
||||||
box_up_to_date: |-
|
box_up_to_date: |-
|
||||||
* '%{name}' (v%{version}) is up to date
|
* '%{name}' (v%{version}) is up to date
|
||||||
|
box_up_to_date_single: |-
|
||||||
|
Your box '%{name}' (v%{version}) is running the latest version.
|
||||||
cfengine_bootstrapping: |-
|
cfengine_bootstrapping: |-
|
||||||
Bootstrapping CFEngine with policy server: %{policy_server}...
|
Bootstrapping CFEngine with policy server: %{policy_server}...
|
||||||
cfengine_bootstrapping_policy_hub: |-
|
cfengine_bootstrapping_policy_hub: |-
|
||||||
|
@ -357,6 +363,15 @@ en:
|
||||||
that this issue can be fixed.
|
that this issue can be fixed.
|
||||||
|
|
||||||
%{error}
|
%{error}
|
||||||
|
box_outdated_no_metadata: |-
|
||||||
|
The box '%{name}' is not a versioned box. The box was added
|
||||||
|
directly instead of from a box catalog. Vagrant can only
|
||||||
|
check the versions of boxes that were added from a catalog
|
||||||
|
such as from the public Vagrant Server.
|
||||||
|
box_outdated_no_box: |-
|
||||||
|
The box '%{name}' isn't downloaded or added yet, so we can't
|
||||||
|
check if it is outdated. Run a `vagrant up` or add the box
|
||||||
|
with `vagrant box add` to download an appropriate version.
|
||||||
box_provider_doesnt_match: |-
|
box_provider_doesnt_match: |-
|
||||||
The box you attempted to add doesn't match the provider you specified.
|
The box you attempted to add doesn't match the provider you specified.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
|
||||||
|
describe Vagrant::Action::Builtin::BoxCheckOutdated do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:app) { lambda { |env| } }
|
||||||
|
let(:env) { {
|
||||||
|
machine: machine,
|
||||||
|
} }
|
||||||
|
|
||||||
|
subject { described_class.new(app, env) }
|
||||||
|
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
isolated_environment.tap do |env|
|
||||||
|
env.vagrantfile("")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:iso_vagrant_env) { iso_env.create_vagrant_env }
|
||||||
|
|
||||||
|
let(:box) do
|
||||||
|
box_dir = iso_env.box3("foo", "1.0", :virtualbox)
|
||||||
|
Vagrant::Box.new("foo", :virtualbox, "1.0", box_dir)
|
||||||
|
end
|
||||||
|
let(:machine) { iso_vagrant_env.machine(iso_vagrant_env.machine_names[0], :dummy) }
|
||||||
|
|
||||||
|
context "no box" do
|
||||||
|
it "raises an exception if the machine doesn't have a box yet" do
|
||||||
|
machine.stub(box: nil)
|
||||||
|
|
||||||
|
app.should_receive(:call).never
|
||||||
|
|
||||||
|
expect { subject.call(env) }.
|
||||||
|
to raise_error(Vagrant::Errors::BoxOutdatedNoBox)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "box with no metadata_url" do
|
||||||
|
let(:box) do
|
||||||
|
box_dir = iso_env.box3("foo", "1.0", :virtualbox)
|
||||||
|
Vagrant::Box.new("foo", :virtualbox, "1.0", box_dir)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
machine.stub(box: box)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises an exception" do
|
||||||
|
app.should_receive(:call).never
|
||||||
|
|
||||||
|
expect { subject.call(env) }.
|
||||||
|
to raise_error(Vagrant::Errors::BoxOutdatedNoMetadata)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with a metadata URL" do
|
||||||
|
let(:metadata_url) do
|
||||||
|
Tempfile.new("vagrant").tap do |f|
|
||||||
|
f.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:box_dir) { iso_env.box3("foo", "1.0", :virtualbox) }
|
||||||
|
|
||||||
|
it "isn't outdated if it isn't" do
|
||||||
|
File.open(metadata_url.path, "w") do |f|
|
||||||
|
f.write(<<-RAW)
|
||||||
|
{
|
||||||
|
"name": "foo/bar",
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"version": "1.0",
|
||||||
|
"providers": [
|
||||||
|
{
|
||||||
|
"name": "virtualbox",
|
||||||
|
"url": "#{iso_env.box2_file(:virtualbox)}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
RAW
|
||||||
|
end
|
||||||
|
|
||||||
|
box = Vagrant::Box.new(
|
||||||
|
"foo", :virtualbox, "1.0", box_dir, metadata_url: metadata_url.path)
|
||||||
|
machine.stub(box: box)
|
||||||
|
|
||||||
|
subject.call(env)
|
||||||
|
|
||||||
|
expect(env[:box_outdated]).to be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is outdated if it is" do
|
||||||
|
File.open(metadata_url.path, "w") do |f|
|
||||||
|
f.write(<<-RAW)
|
||||||
|
{
|
||||||
|
"name": "foo/bar",
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.5",
|
||||||
|
"providers": [
|
||||||
|
{
|
||||||
|
"name": "virtualbox",
|
||||||
|
"url": "#{iso_env.box2_file(:virtualbox)}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
RAW
|
||||||
|
end
|
||||||
|
|
||||||
|
box = Vagrant::Box.new(
|
||||||
|
"foo", :virtualbox, "1.0", box_dir, metadata_url: metadata_url.path)
|
||||||
|
machine.stub(box: box)
|
||||||
|
|
||||||
|
subject.call(env)
|
||||||
|
|
||||||
|
expect(env[:box_outdated]).to be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "isn't outdated if the newer box is for another provider" do
|
||||||
|
File.open(metadata_url.path, "w") do |f|
|
||||||
|
f.write(<<-RAW)
|
||||||
|
{
|
||||||
|
"name": "foo/bar",
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.5",
|
||||||
|
"providers": [
|
||||||
|
{
|
||||||
|
"name": "vmware",
|
||||||
|
"url": "#{iso_env.box2_file(:vmware)}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
RAW
|
||||||
|
end
|
||||||
|
|
||||||
|
box = Vagrant::Box.new(
|
||||||
|
"foo", :virtualbox, "1.0", box_dir, metadata_url: metadata_url.path)
|
||||||
|
machine.stub(box: box)
|
||||||
|
|
||||||
|
subject.call(env)
|
||||||
|
|
||||||
|
expect(env[:box_outdated]).to be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue