Class: Ridley::CookbookResource

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

Instance Method Summary collapse

Methods inherited from Resource

#connection, #from_file, #from_json, #new, representation, represented_by, resource_path, set_resource_path

Constructor Details

#initialize(connection_registry, client_name, client_key, options = {}) ⇒ CookbookResource

Returns a new instance of CookbookResource.



10
11
12
13
# File 'lib/ridley/resources/cookbook_resource.rb', line 10

def initialize(connection_registry, client_name, client_key, options = {})
  super(connection_registry)
  @sandbox_resource = SandboxResource.new_link(connection_registry, client_name, client_key, options)
end

Instance Method Details

#allHash

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

Examples:

return value

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

Returns:

  • (Hash)

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



30
31
32
33
34
35
36
37
38
# File 'lib/ridley/resources/cookbook_resource.rb', line 30

def all
  response = request(:get, self.class.resource_path, num_versions: "all")

  {}.tap do |cookbooks|
    response.each do |name, details|
      cookbooks[name] = details["versions"].collect { |version| version["version"] }
    end
  end
end

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

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

Parameters:

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

    a customizable set of options

Options Hash (options):

  • purge (Boolean) — default: false

Returns:

  • (Boolean)


48
49
50
51
52
53
54
55
56
57
58
# File 'lib/ridley/resources/cookbook_resource.rb', line 48

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

  request(:delete, url)
  true
rescue AbortError => ex
  return nil if ex.cause.is_a?(Errors::HTTPNotFound)
  abort(ex.cause)
end

#delete_all(name, options = {}) ⇒ Object

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

Parameters:

  • name (String)

    name of the cookbook to delete

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

    a customizable set of options

Options Hash (options):

  • purge (Boolean) — default: false


66
67
68
# File 'lib/ridley/resources/cookbook_resource.rb', line 66

def delete_all(name, options = {})
  versions(name).collect { |version| future(:delete, name, version, options) }.map(&:value)
end

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

Download the entire cookbook

Parameters:

  • 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

Raises:



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

def download(name, version, destination = Dir.mktmpdir)
  if cookbook = find(name, version)
    cookbook.download(destination)
  else
    abort Errors::ResourceNotFound.new("cookbook #{name} (#{version}) was not found")
  end
end

#find(object, version) ⇒ nil, CookbookResource

Parameters:

  • object (String, #chef_id)
  • version (String)

Returns:



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

def find(object, version)
  chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
  new(request(:get, "#{self.class.resource_path}/#{chef_id}/#{version}"))
rescue AbortError => ex
  return nil if ex.cause.is_a?(Errors::HTTPNotFound)
  abort(ex.cause)
end

#latest_version(name) ⇒ String?

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

Parameters:

  • name (String)

Returns:

  • (String, nil)

Raises:



109
110
111
112
113
114
115
# File 'lib/ridley/resources/cookbook_resource.rb', line 109

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

  ver.nil? ? nil : ver.to_s
end

#satisfy(name, constraint) ⇒ CookbookResource?

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

Parameters:

  • name (String)

    name of the cookbook

  • constraint (String, Semverse::Constraint)

    constraint to solve for

Returns:

  • (CookbookResource, nil)

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

Raises:



128
129
130
131
132
133
# File 'lib/ridley/resources/cookbook_resource.rb', line 128

def satisfy(name, constraint)
  version = Semverse::Constraint.satisfy_best(constraint, versions(name)).to_s
  find(name, version)
rescue Semverse::NoSolutionError
  nil
end

#update(cookbook, options = {}) ⇒ Hash Also known as: create

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

Parameters:

  • cookbook (Ridley::Chef::Cookbook)

    the cookbook to save

  • 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)

Raises:

  • (Ridley::Errors::FrozenCookbook)

    if a cookbook of the same name and version already exists on the remote Chef server and is frozen. If the :force option is provided the given cookbook will be saved regardless.



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/ridley/resources/cookbook_resource.rb', line 154

def update(cookbook, options = {})
  options = options.reverse_merge(force: false, freeze: false)

  cookbook.frozen = options[:freeze]

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

  request(:put, url, cookbook.to_json)
rescue AbortError => ex
  if ex.cause.is_a?(Errors::HTTPConflict)
    abort Ridley::Errors::FrozenCookbook.new(ex)
  end
  abort(ex.cause)
end

#upload(path, options = {}) ⇒ Hash

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

Parameters:

  • path (String)

    path to a cookbook on local disk

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

    a customizable set of options

Options Hash (options):

  • :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)


186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/ridley/resources/cookbook_resource.rb', line 186

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

  unless (existing = find(cookbook.cookbook_name, cookbook.version)).nil?
    if existing.frozen? && options[:force] == false
      msg = "The cookbook #{cookbook.cookbook_name} (#{cookbook.version}) already exists and is"
      msg << " frozen on the Chef server. Use the 'force' option to override."
      abort Ridley::Errors::FrozenCookbook.new(msg)
    end
  end

  if options[:validate]
    cookbook.validate
  end

  # Compile metadata on upload if it hasn't been compiled already
  unless cookbook.compiled_metadata?
     = cookbook.
    cookbook.reload
  end

  # Skip uploading the raw metadata (metadata.rb). The raw metadata is unecessary for the
  # client, and this is required until compiled metadata (metadata.json) takes precedence over
  # raw metadata in the Chef-Client.
  #
  # We can change back to including the raw metadata in the future after this has been fixed or
  # just remove these comments. There is no circumstance that I can currently think of where
  # raw metadata should ever be read by the client.
  #
  # - Jamie
  #
  # See the following tickets for more information:
  #   * https://tickets.opscode.com/browse/CHEF-4811
  #   * https://tickets.opscode.com/browse/CHEF-4810
  cookbook.manifest[:root_files].reject! do |file|
    File.basename(file[:name]).downcase == Ridley::Chef::Cookbook::Metadata::RAW_FILE_NAME
  end

  checksums = cookbook.checksums.dup
  sandbox   = sandbox_resource.create(checksums.keys.sort)

  sandbox.upload(checksums)
  sandbox.commit
  update(cookbook, Ridley::Helpers.options_slice(options, :force, :freeze))
ensure
  # Destroy the compiled metadata only if it was created
  File.delete() unless .nil?
end

#versions(name) ⇒ Array<String>

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

Examples:

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

Parameters:

  • name (String)

Returns:

  • (Array<String>)

Raises:



246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/ridley/resources/cookbook_resource.rb', line 246

def versions(name)
  response = request(:get, "#{self.class.resource_path}/#{name}")

  response[name]["versions"].collect do |cb_ver|
    cb_ver["version"]
  end
rescue AbortError => ex
  if ex.cause.is_a?(Errors::HTTPNotFound)
    abort Errors::ResourceNotFound.new(ex)
  end
  abort(ex.cause)
end