Merge pull request #2565 from mitchellh/f-box-checksum

Implement box checksumming
This commit is contained in:
Mitchell Hashimoto 2013-12-03 11:33:16 -08:00
commit 2e199d0889
9 changed files with 121 additions and 4 deletions

View File

@ -2,6 +2,7 @@ require "digest/sha1"
require "log4r"
require "vagrant/util/downloader"
require "vagrant/util/file_checksum"
require "vagrant/util/platform"
module Vagrant
@ -18,6 +19,22 @@ module Vagrant
def call(env)
@download_interrupted = false
# Determine the checksum type to use
checksum = (env[:box_checksum] || "").to_s
checksum_klass = case env[:box_checksum_type].to_sym
when nil
nil
when :md5
Digest::MD5
when :sha1
Digest::SHA1
when :sha256
Digest::SHA2
else
raise Errors::BoxChecksumInvalidType,
type: env[:box_checksum_type].to_s
end
# Go through each URL and attempt to download it
download_error = nil
download_url = nil
@ -45,6 +62,20 @@ module Vagrant
# If all the URLs failed, then raise an exception
raise download_error if download_error
if checksum_klass
@logger.info("Validating checksum with #{checksum_klass}")
@logger.info("Expected checksum: #{checksum}")
env[:ui].info(I18n.t("vagrant.actions.box.add.checksumming",
name: env[:box_name]))
actual = FileChecksum.new(@temp_path, checksum_klass).checksum
if actual != checksum
raise Errors::BoxChecksumMismatch,
actual: actual,
expected: checksum
end
end
box_formats = env[:box_provider]
if box_formats
# Determine the formats a box can support and allow the box to

View File

@ -41,6 +41,8 @@ module Vagrant
box_name = env[:machine].config.vm.box
box_url = env[:machine].config.vm.box_url
box_download_ca_cert = env[:machine].config.vm.box_download_ca_cert
box_download_checksum = env[:machine].config.vm.box_download_checksum
box_download_checksum_type = env[:machine].config.vm.box_download_checksum_type
box_download_client_cert = env[:machine].config.vm.box_download_client_cert
box_download_insecure = env[:machine].config.vm.box_download_insecure
@ -69,8 +71,10 @@ module Vagrant
begin
env[:action_runner].run(Vagrant::Action.action_box_add, {
:box_download_ca_cert => box_download_ca_cert,
:box_checksum => box_download_checksum,
:box_checksum_type => box_download_checksum_type,
:box_client_cert => box_download_client_cert,
:box_download_ca_cert => box_download_ca_cert,
:box_download_insecure => box_download_insecure,
:box_name => box_name,
:box_provider => box_formats,

View File

@ -120,6 +120,14 @@ module Vagrant
error_key(:already_exists, "vagrant.actions.box.unpackage")
end
class BoxChecksumInvalidType < VagrantError
error_key(:box_checksum_invalid_type)
end
class BoxChecksumMismatch < VagrantError
error_key(:box_checksum_mismatch)
end
class BoxConfigChangingBox < VagrantError
error_key(:box_config_changing_box)
end

View File

@ -8,7 +8,7 @@ class DigestClass
end
class FileChecksum
BUFFER_SIZE = 1024
BUFFER_SIZE = 16328
# Initializes an object to calculate the checksum of a file. The given
# ``digest_klass`` should implement the ``DigestClass`` interface. Note
@ -16,7 +16,7 @@ class FileChecksum
# Digest::MD5, Digest::SHA1, etc.
def initialize(path, digest_klass)
@digest_klass = digest_klass
@path = path
@path = path
end
# This calculates the checksum of the file and returns it as a
@ -24,7 +24,7 @@ class FileChecksum
#
# @return [String]
def checksum
digest= @digest_klass.new
digest = @digest_klass.new
File.open(@path, "r") do |f|
while !f.eof

View File

@ -11,6 +11,14 @@ module VagrantPlugins
o.banner = "Usage: vagrant box add <name> <url> [--provider provider] [-h]"
o.separator ""
o.on("--checksum VALUE", String, "Checksum") do |c|
options[:checksum] = c
end
o.on("--checksum-type VALUE", String, "Checksum type") do |c|
options[:checksum_type] = c.to_sym
end
o.on("-c", "--clean", "Remove old temporary download if it exists.") do |c|
options[:clean] = c
end
@ -51,6 +59,8 @@ module VagrantPlugins
:box_name => argv[0],
:box_provider => provider,
:box_url => argv[1],
:box_checksum_type => options[:checksum_type],
:box_checksum => options[:checksum],
:box_clean => options[:clean],
:box_force => options[:force],
:box_download_ca_cert => options[:ca_cert],

View File

@ -19,6 +19,8 @@ module VagrantPlugins
attr_accessor :box
attr_accessor :box_url
attr_accessor :box_download_ca_cert
attr_accessor :box_download_checksum
attr_accessor :box_download_checksum_type
attr_accessor :box_download_client_cert
attr_accessor :box_download_insecure
attr_accessor :graceful_halt_timeout
@ -30,6 +32,8 @@ module VagrantPlugins
def initialize
@boot_timeout = UNSET_VALUE
@box_download_ca_cert = UNSET_VALUE
@box_download_checksum = UNSET_VALUE
@box_download_checksum_type = UNSET_VALUE
@box_download_client_cert = UNSET_VALUE
@box_download_insecure = UNSET_VALUE
@box_url = UNSET_VALUE
@ -256,6 +260,8 @@ module VagrantPlugins
# Defaults
@boot_timeout = 300 if @boot_timeout == UNSET_VALUE
@box_download_ca_cert = nil if @box_download_ca_cert == UNSET_VALUE
@box_download_checksum = nil if @box_download_checksum == UNSET_VALUE
@box_download_checksum_type = nil if @box_download_checksum_type == UNSET_VALUE
@box_download_client_cert = nil if @box_download_client_cert == UNSET_VALUE
@box_download_insecure = false if @box_download_insecure == UNSET_VALUE
@box_url = nil if @box_url == UNSET_VALUE
@ -264,6 +270,10 @@ module VagrantPlugins
@hostname = nil if @hostname == UNSET_VALUE
@hostname = @hostname.to_s if @hostname
if @box_download_checksum_type
@box_download_checksum_type = @box_download_checksum_type.to_sym
end
# Make sure the box URL is an array if it is set
if @box_url && !@box_url.is_a?(Array)
@box_url = [@box_url]
@ -385,6 +395,16 @@ module VagrantPlugins
end
end
if box_download_checksum_type
if box_download_checksum == ""
errors << I18n.t("vagrant.config.vm.box_download_checksum_blank")
end
else
if box_download_checksum != ""
errors << I18n.t("vagrant.config.vm.box_download_checksum_notblank")
end
end
has_nfs = false
used_guest_paths = Set.new
@__synced_folders.each do |id, options|

View File

@ -177,6 +177,18 @@ en:
If the box appears to be booting properly, you may want to increase
the timeout ("config.vm.boot_timeout") value.
box_checksum_invalid_type: |-
The specified checksum type is not supported by Vagrant: %{type}.
Vagrant supports the following checksum types:
md5, sha1, sha256
box_checksum_mismatch: |-
The checksum of the dowloaded box did not match the expected
value. Please verify that you have the proper URL setup and that
you're downloading the proper file.
Expected: %{expected}
Received: %{actual}
box_config_changing_box: |-
While loading the Vagrantfile, the provider override specified
a new box. This box, in turn, specified a different box. This isn't
@ -722,6 +734,10 @@ en:
base_mac_invalid: "Base MAC address for eth0/NAT must be set. Contact box maintainer for more information."
box_download_ca_cert_not_found: |-
"box_download_ca_cert" file not found: %{path}
box_download_checksum_blank: |-
Checksum type specified but "box_download_checksum" is blank
box_download_checksum_notblank: |-
Checksum specified but must also specify "box_download_checksum_type"
box_missing: "A box must be specified."
box_not_found: "The box '%{name}' could not be found."
hostname_invalid_characters: |-
@ -1121,6 +1137,8 @@ en:
Extracting box...
added: |-
Successfully added box '%{name}' with provider '%{provider}'!
checksumming: |-
Calculating and comparing box checksum...
destroy:
destroying: "Deleting box '%{name}'..."
download:

View File

@ -44,6 +44,15 @@ after the initial download.
* `--cert CERTFILE` - A client certificate to use when downloading the box, if
necessary.
* `--checksum VALUE` - A checksum for the box that is downloaded. If specified,
Vagrant will compare this checksum to what is actually downloaded and will
error if the checksums do not match. This is highly recommended since
box files are so large. If this is specified, `--checksum-type` must
also be specified.
* `--checksum-type TYPE` - The type of checksum that `--checksum` is if it
is specified. Supported values are currently "md5", "sha1", and "sha256".
* `--clean` - If given, Vagrant will remove any old temporary files from
prior downloads of the same URL. This is useful if you don't want Vagrant
to resume a download from a previous point, perhaps because the contents

View File

@ -23,6 +23,23 @@ the installed boxes on the system.
<hr>
`config.vm.box_download_checksum` - The checksum of the box specified by
`config.vm.box_url`. If not specified, no checksum comparison will be done.
If specified, Vagrant will compare the checksum of the downloaded box to
this value and error if they do not match. Checksum checking is only done
when Vagrant must download the box.
If this is specified, then `config.vm.box_download_checksum_type` must
also be specified.
<hr>
`config.vm.box_download_checksum_type` - The type of checksum specified
by `config.vm.box_download_checksum` (if any). Supported values are
currently "md5", "sha1", and "sha256".
<hr>
`config.vm.box_download_client_cert` - Path to a client certificate to
use when downloading the box, if it is necessary. By default, no client
certificate is used to download the box.