class Ridley::SandboxUploader

@api private

Attributes

client_key[R]
client_name[R]
options[R]

Public Class Methods

checksum(io, digest = Digest::MD5.new) click to toggle source

Return the checksum of the contents of the file at the given filepath

@param [String] io

a filepath or an IO

@param [Digest::Base] digest

@return [String]

the binary checksum of the contents of the file
# File lib/ridley/sandbox_uploader.rb, line 13
def checksum(io, digest = Digest::MD5.new)
  while chunk = io.read(1024 * 8)
    digest.update(chunk)
  end
  digest.hexdigest
end
checksum64(io) click to toggle source

Return a base64 encoded checksum of the contents of the given file. This is the expected format of sandbox checksums given to the Chef Server.

@param [String] io

a filepath or an IO

@return [String]

a base64 encoded checksum
# File lib/ridley/sandbox_uploader.rb, line 28
def checksum64(io)
  Base64.encode64([checksum(io)].pack("H*")).strip
end
new(client_name, client_key, options = {}) click to toggle source
# File lib/ridley/sandbox_uploader.rb, line 39
def initialize(client_name, client_key, options = {})
  @client_name = client_name
  @client_key  = client_key
  @options     = options
end

Public Instance Methods

upload(sandbox, chk_id, file) click to toggle source

Upload one file into the sandbox for the given checksum id

@param [Ridley::SandboxObject] sandbox @param [String] chk_id

checksum of the file being uploaded

@param [String, read] file

a filepath or an IO

@raise [Errors::ChecksumMismatch]

if the given file does not match the expected checksum

@return [Hash, nil]

# File lib/ridley/sandbox_uploader.rb, line 57
def upload(sandbox, chk_id, file)
  checksum = sandbox.checksum(chk_id)

  unless checksum[:needs_upload]
    return nil
  end

  io                  = file.respond_to?(:read) ? file : File.new(file, 'rb')
  calculated_checksum = self.class.checksum64(io)
  expected_checksum   = Base64.encode64([chk_id].pack('H*')).strip

  unless calculated_checksum == expected_checksum
    raise Errors::ChecksumMismatch,
      "Error uploading #{chk_id}. Expected #{expected_checksum} but got #{calculated_checksum}"
  end

  headers = {
    'Content-Type' => 'application/x-binary',
    'content-md5' => calculated_checksum
  }
  
  url         = URI(checksum[:url])
  upload_path = url.path
  url.path    = ""

  # versions prior to OSS Chef 11 will strip the port to upload the file to in the checksum
  # url returned. This will ensure we are uploading to the proper location.
  if sandbox.send(:resource).connection.foss?
    url.port = URI(sandbox.send(:resource).connection.server_url).port
  end

  begin
    io.rewind

    Faraday.new(url, self.options) do |c|
      c.response :chef_response
      c.response :follow_redirects
      c.request :chef_auth, self.client_name, self.client_key
      c.adapter :httpclient
    end.put(upload_path, io.read, headers)
  rescue Ridley::Errors::HTTPError => ex
    abort(ex)
  end
end