Class: Ridley::CookbookResource

Inherits:
Resource
  • Object
show all
Includes:
Logging
Defined in:
lib/ridley/resources/cookbook_resource.rb

Overview

Author:

Constant Summary collapse

FILE_TYPES =
[
  :resources,
  :providers,
  :recipes,
  :definitions,
  :libraries,
  :attributes,
  :files,
  :templates,
  :root_files
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Logging

logger, #logger, set_logger

Methods inherited from Resource

#<=>, #==, chef_id, #chef_id, chef_json_class, chef_type, #eql?, #hash, #initialize, #reload, resource_path, #save, set_chef_id, set_chef_json_class, set_chef_type, set_resource_path, #update

Constructor Details

This class inherits a constructor from Ridley::Resource

Class Method Details

.all(client) ⇒ Hash

List all of the cookbooks and their versions present on the remote

Examples:

return value

{
  "ant" => [
    "0.10.1"
  ],
  "apache2" => [
    "1.4.0"
  ]
} 

Parameters:

Returns:

  • (Hash)

    a hash containing keys which represent cookbook names and values which contain an array of strings representing the available versions


22
23
24
25
26
27
28
29
30
# File 'lib/ridley/resources/cookbook_resource.rb', line 22

def all(client)
  response = client.connection.get(self.resource_path).body
  
  {}.tap do |cookbooks|
    response.each do |name, details|
      cookbooks[name] = details["versions"].collect { |version| version["version"] }
    end
  end
end

.create(*args) ⇒ Object

Raises:

  • (NotImplementedError)

32
33
34
# File 'lib/ridley/resources/cookbook_resource.rb', line 32

def create(*args)
  raise NotImplementedError
end

.delete(client, name, version, options = {}) ⇒ Boolean

Delete a cookbook of the given name and version on the remote Chef server

Parameters:

  • client (Ridley::Client)
  • name (String)
  • version (String)
  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • purge (Boolean) — default: false

Returns:

  • (Boolean)

45
46
47
48
49
50
51
52
53
54
# File 'lib/ridley/resources/cookbook_resource.rb', line 45

def delete(client, name, version, options = {})
  options = options.reverse_merge(purge: false)
  url = "#{self.resource_path}/#{name}/#{version}"
  url += "?purge=true" if options[:purge]

  client.connection.delete(url).body
  true
rescue Errors::HTTPNotFound
  true
end

.delete_all(client, name, options = {}) ⇒ Object

Delete all of the versions of a given cookbook on the remote Chef server

Parameters:

  • client (Ridley::Client)
  • name (String)

    name of the cookbook to delete

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • purge (Boolean) — default: false

63
64
65
66
67
# File 'lib/ridley/resources/cookbook_resource.rb', line 63

def delete_all(client, name, options = {})
  versions(client, name).each do |version|
    delete(client, name, version, options)
  end
end

.download(client, name, version, destination = Dir.mktmpdir) ⇒ String

Download the entire cookbook

Parameters:

  • client (Ridley::Client)
  • name (String)
  • version (String)
  • destination (String) (defaults to: Dir.mktmpdir)

    (Dir.mktmpdir) the place to download the cookbook too. If no value is provided the cookbook will be downloaded to a temporary location

Returns:

  • (String)

    the path to the directory the cookbook was downloaded to


80
81
82
83
84
85
86
# File 'lib/ridley/resources/cookbook_resource.rb', line 80

def download(client, name, version, destination = Dir.mktmpdir)
  cookbook = find(client, name, version)
  
  unless cookbook.nil?
    cookbook.download(destination)
  end
end

.find(client, object, version) ⇒ nil, CookbookResource

Parameters:

Returns:


93
94
95
96
97
# File 'lib/ridley/resources/cookbook_resource.rb', line 93

def find(client, object, version)
  find!(client, object, version)
rescue Errors::HTTPNotFound
  nil
end

.find!(client, object, version) ⇒ CookbookResource

Parameters:

Returns:

Raises:


107
108
109
110
# File 'lib/ridley/resources/cookbook_resource.rb', line 107

def find!(client, object, version)
  chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
  new(client, client.connection.get("#{self.resource_path}/#{chef_id}/#{version}").body)
end

.latest_version(client, name) ⇒ String?

Return the latest version of the given cookbook found on the remote Chef server

Parameters:

Returns:

  • (String, nil)

118
119
120
121
122
123
124
# File 'lib/ridley/resources/cookbook_resource.rb', line 118

def latest_version(client, name)
  ver = versions(client, name).collect do |version|
    Solve::Version.new(version)
  end.sort.last

  ver.nil? ? nil : ver.to_s
end

.satisfy(client, name, constraint) ⇒ CookbookResource?

Return the version of the given cookbook which best stasifies the given constraint

Parameters:

  • client (Ridley::Client)
  • name (String)

    name of the cookbook

  • constraint (String, Solve::Constraint)

    constraint to solve for

Returns:

  • (CookbookResource, nil)

    returns the cookbook resource for the best solution or nil if no solution exists


136
137
138
139
140
141
# File 'lib/ridley/resources/cookbook_resource.rb', line 136

def satisfy(client, name, constraint)
  version = Solve::Solver.satisfy_best(constraint, versions(client, name)).to_s
  find(client, name, version)
rescue Solve::Errors::NoSolutionError
  nil
end

.save(client, name, version, manifest, options = {}) ⇒ Hash

Save a new Cookbook Version of the given name, version with the given manifest of files and checksums.

Parameters:

  • client (Ridley::Client)
  • name (String)
  • version (String)
  • manifest (String)

    a JSON blob containing file names, file paths, and checksums for each that describe the cookbook version being uploaded.

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :force (Boolean)

    Upload the Cookbook even if the version already exists and is frozen on the target Chef Server

  • :freeze (Boolean)

    Freeze the uploaded Cookbook on the Chef Server so that it cannot be overwritten

Returns:

  • (Hash)

161
162
163
164
165
166
167
168
# File 'lib/ridley/resources/cookbook_resource.rb', line 161

def save(client, name, version, manifest, options = {})
  options.reverse_merge(force: false, freeze: false)

  url = "cookbooks/#{name}/#{version}"
  url << "?force=true" if options[:force]

  client.connection.put(url, manifest)
end

.update(*args) ⇒ Object

Raises:

  • (NotImplementedError)

170
171
172
# File 'lib/ridley/resources/cookbook_resource.rb', line 170

def update(*args)
  raise NotImplementedError
end

.upload(client, path, options = {}) ⇒ Hash

Uploads a cookbook to the remote Chef server from the contents of a filepath

Parameters:

  • client (Ridley::Client)
  • path (String)

    path to a cookbook on local disk

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :name (String)

    automatically populated by the metadata of the cookbook at the given path, but in the event that the metadata does not contain a name it can be specified with this option

  • :force (Boolean) — default: false

    Upload the Cookbook even if the version already exists and is frozen on the target Chef Server

  • :freeze (Boolean) — default: false

    Freeze the uploaded Cookbook on the Chef Server so that it cannot be overwritten

  • :validate (Boolean) — default: true

    Validate the contents of the cookbook before uploading

Returns:

  • (Hash)

194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/ridley/resources/cookbook_resource.rb', line 194

def upload(client, path, options = {})
  options   = options.reverse_merge(validate: true, force: false, freeze: false)
  cookbook  = Ridley::Chef::Cookbook.from_path(path, options.slice(:name))

  if options[:validate]
    cookbook.validate
  end

  name      = options[:name] || cookbook.name
  checksums = cookbook.checksums.dup
  sandbox   = client.sandbox.create(checksums.keys)

  sandbox.upload(checksums)
  sandbox.commit
  save(client, name, cookbook.version, cookbook.to_json, options.slice(:force, :freeze))
end

.versions(client, name) ⇒ Array<String>

Return a list of versions for the given cookbook present on the remote Chef server

Examples:

versions(client, "nginx") => [ "1.0.0", "1.2.0" ]

Parameters:

Returns:

  • (Array<String>)

220
221
222
223
224
225
226
# File 'lib/ridley/resources/cookbook_resource.rb', line 220

def versions(client, name)
  response = client.connection.get("#{self.resource_path}/#{name}").body

  response[name]["versions"].collect do |cb_ver|
    cb_ver["version"]
  end
end

Instance Method Details

#download(destination = Dir.mktmpdir) ⇒ String

Download the entire cookbook

Parameters:

  • destination (String) (defaults to: Dir.mktmpdir)

    (Dir.mktmpdir) the place to download the cookbook too. If no value is provided the cookbook will be downloaded to a temporary location

Returns:

  • (String)

    the path to the directory the cookbook was downloaded to


304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
# File 'lib/ridley/resources/cookbook_resource.rb', line 304

def download(destination = Dir.mktmpdir)
  destination = File.expand_path(destination)
  log.debug { "downloading cookbook: '#{name}'" }

  FILE_TYPES.each do |filetype|
    next unless manifest.has_key?(filetype)

    manifest[filetype].each do |file|
      file_destination = File.join(destination, file[:path].gsub('/', File::SEPARATOR))
      FileUtils.mkdir_p(File.dirname(file_destination))
      download_file(filetype, file[:path], file_destination)
    end
  end

  destination
end

#download_file(filetype, path, destination) ⇒ nil

Download a single file from a cookbook

Parameters:

  • filetype (#to_sym)

    the type of file to download. These are broken up into the following types in Chef:

    - attribute (unsupported until resolved https://github.com/reset/chozo/issues/17)
    - definition
    - file
    - library
    - provider
    - recipe
    - resource
    - root_file
    - template
    

    these types are where the files are stored in your cookbook's structure. For example, a recipe would be stored in the recipes directory while a root_file is stored at the root of your cookbook

  • path (String)

    path of the file to download

  • destination (String)

    where to download the file to

Returns:

  • (nil)

343
344
345
# File 'lib/ridley/resources/cookbook_resource.rb', line 343

def download_file(filetype, path, destination)
  download_fun(filetype).call(path, destination)
end

#manifestHash

A hash containing keys for all of the different cookbook filetypes with values representing each file of that type this cookbook contains

Examples:

{
  root_files: [
    {
      :name => "afile.rb",
      :path => "files/ubuntu-9.10/afile.rb",
      :checksum => "2222",
      :specificity => "ubuntu-9.10"
    },
  ],
  templates: [ manifest_record1, ... ],
  ...
}

Returns:

  • (Hash)

365
366
367
368
369
370
371
# File 'lib/ridley/resources/cookbook_resource.rb', line 365

def manifest
  {}.tap do |manifest|
    FILE_TYPES.each do |filetype|
      manifest[filetype] = get_attribute(filetype)
    end
  end
end

#to_sObject


373
374
375
# File 'lib/ridley/resources/cookbook_resource.rb', line 373

def to_s
  "#{name}: #{manifest}"
end