Class: Pantry::Chef::UploadCookbook

Inherits:
Pantry::Command
  • Object
show all
Defined in:
lib/pantry/chef/upload_cookbook.rb

Overview

Given a cookbook, upload it to the server. A given cookbook is stored in two locations. The cookbook tarball the Server receives is stored in Pantry.root/chef/cookbook-cache/.tgz to keep it available for sending back down to Clients who need the cookbook. To facilitate using the Chef library for dependency checks, the Server also unpacks the cookbook locally to Pantry.root/chef/cookbooks/.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cookbook_path = nil) ⇒ UploadCookbook

Returns a new instance of UploadCookbook.



18
19
20
# File 'lib/pantry/chef/upload_cookbook.rb', line 18

def initialize(cookbook_path = nil)
  @cookbook_path = cookbook_path
end

Instance Attribute Details

#cookbook_tarballObject (readonly)

Returns the value of attribute cookbook_tarball.



16
17
18
# File 'lib/pantry/chef/upload_cookbook.rb', line 16

def cookbook_tarball
  @cookbook_tarball
end

Instance Method Details

#perform(message) ⇒ Object

Server receives request message for a new Cookbook Upload. Checks that the upload is valid Fires off an upload receiver and returns the UUID for the client to use



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/pantry/chef/upload_cookbook.rb', line 63

def perform(message)
  cookbook_name     = message[:cookbook_name]
  cookbook_size     = message[:cookbook_size]
  cookbook_checksum = message[:cookbook_checksum]

  cookbook_cache = Pantry.root.join("chef", "cookbook-cache")
  cookbook_home = Pantry.root.join("chef", "cookbooks")
  FileUtils.mkdir_p(cookbook_cache)
  FileUtils.mkdir_p(cookbook_home)

  save_tar_path = cookbook_cache.join("#{cookbook_name}.tgz")

  uploader_info = server.receive_file(cookbook_size, cookbook_checksum)
  uploader_info.on_complete do
    # Store the tarball into the cookbook cache
    FileUtils.mv uploader_info.uploaded_path, save_tar_path

    # Unpack the cookbook itself
    stdout, stderr = Open3.capture2e(
      "tar", "-xzC", cookbook_home.to_s, "-f", save_tar_path.to_s
    )
    Pantry.logger.debug("[Upload Cookbook] Unpack cookbook #{stdout.inspect}, #{stderr.inspect}")
  end

  [true, uploader_info.receiver_uuid, uploader_info.file_uuid]
rescue => ex
  [false, ex.message]
end

#prepare_message(options) ⇒ Object

Multi-step prepratory step here:

  • Find the cookbook in question

  • Figure out if it’s a valid cookbook (do some checks Chef doesn’t itself do)

  • Tar up the cookbook

  • Figure out size and a checksum

  • Package all this information into the message to send to the server

Raises:



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/pantry/chef/upload_cookbook.rb', line 30

def prepare_message(options)
  require 'chef/cookbook_loader'

  cookbook_name = File.basename(@cookbook_path)
  cookbooks_dir = File.dirname(@cookbook_path)

  loader   = ::Chef::CookbookLoader.new([cookbooks_dir])
  cookbook = loader.load_cookbooks[cookbook_name]

  raise UnknownCookbook, "Unable to find cookbook at #{@cookbook_path}" unless cookbook
  raise MissingMetadata, "No metadata.rb found for cookbook at #{@cookbook_path}" unless File.exist?(File.join(@cookbook_path, "metadata.rb"))

  tempfile = Tempfile.new(cookbook_name)
  @cookbook_tarball = "#{tempfile.path}.tgz"
  tempfile.unlink

  # TODO Handle if this fails?
  Dir.chdir(cookbooks_dir) do
    Open3.capture2("tar", "czf", @cookbook_tarball, cookbook_name)
  end

  Pantry.ui.say("Uploading cookbook #{cookbook_name}...")

  message = super
  message[:cookbook_name]     = cookbook..name
  message[:cookbook_size]     = File.size(@cookbook_tarball)
  message[:cookbook_checksum] = Pantry.file_checksum(@cookbook_tarball)
  message
end

#receive_server_response(response) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/pantry/chef/upload_cookbook.rb', line 92

def receive_server_response(response)
  upload_allowed = response.body[0]

  Pantry.logger.debug("[Upload Cookbook] #{response.inspect}")

  if upload_allowed == "true"
    send_info = client.send_file(@cookbook_tarball,
                                 response.body[1],
                                 response.body[2])
    send_info.wait_for_finish
  else
    Pantry.ui.say("ERROR: #{response.body[1]}")
  end
end