ridley 0.10.2 → 0.11.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/README.md +147 -216
  2. data/lib/ridley.rb +2 -0
  3. data/lib/ridley/bootstrap_bindings/unix_template_binding.rb +21 -25
  4. data/lib/ridley/bootstrap_bindings/windows_template_binding.rb +29 -34
  5. data/lib/ridley/bootstrapper.rb +2 -2
  6. data/lib/ridley/bootstrapper/context.rb +5 -5
  7. data/lib/ridley/chef.rb +0 -1
  8. data/lib/ridley/chef/cookbook.rb +0 -9
  9. data/lib/ridley/chef_object.rb +128 -0
  10. data/lib/ridley/chef_objects.rb +3 -0
  11. data/lib/ridley/chef_objects/client_object.rb +55 -0
  12. data/lib/ridley/chef_objects/cookbook_object.rb +190 -0
  13. data/lib/ridley/chef_objects/data_bag_item_obect.rb +104 -0
  14. data/lib/ridley/chef_objects/data_bag_object.rb +31 -0
  15. data/lib/ridley/chef_objects/environment_object.rb +59 -0
  16. data/lib/ridley/chef_objects/node_object.rb +161 -0
  17. data/lib/ridley/chef_objects/role_object.rb +62 -0
  18. data/lib/ridley/chef_objects/sandbox_object.rb +58 -0
  19. data/lib/ridley/client.rb +76 -45
  20. data/lib/ridley/connection.rb +1 -1
  21. data/lib/ridley/errors.rb +8 -1
  22. data/lib/ridley/host_connector.rb +26 -6
  23. data/lib/ridley/host_connector/ssh.rb +3 -3
  24. data/lib/ridley/host_connector/ssh/worker.rb +7 -9
  25. data/lib/ridley/host_connector/winrm/worker.rb +4 -5
  26. data/lib/ridley/mixin/bootstrap_binding.rb +1 -12
  27. data/lib/ridley/resource.rb +51 -171
  28. data/lib/ridley/resources/client_resource.rb +18 -68
  29. data/lib/ridley/resources/cookbook_resource.rb +181 -381
  30. data/lib/ridley/resources/data_bag_item_resource.rb +55 -161
  31. data/lib/ridley/resources/data_bag_resource.rb +20 -61
  32. data/lib/ridley/resources/environment_resource.rb +9 -64
  33. data/lib/ridley/resources/node_resource.rb +135 -311
  34. data/lib/ridley/resources/role_resource.rb +1 -57
  35. data/lib/ridley/resources/sandbox_resource.rb +80 -65
  36. data/lib/ridley/resources/search_resource.rb +99 -0
  37. data/lib/ridley/sandbox_uploader.rb +12 -52
  38. data/lib/ridley/version.rb +1 -1
  39. data/spec/acceptance/bootstrapping_spec.rb +1 -1
  40. data/spec/acceptance/client_resource_spec.rb +15 -37
  41. data/spec/acceptance/data_bag_item_resource_spec.rb +8 -14
  42. data/spec/acceptance/data_bag_resource_spec.rb +1 -1
  43. data/spec/acceptance/environment_resource_spec.rb +13 -22
  44. data/spec/acceptance/node_resource_spec.rb +10 -29
  45. data/spec/acceptance/role_resource_spec.rb +14 -13
  46. data/spec/acceptance/sandbox_resource_spec.rb +2 -2
  47. data/spec/support/shared_examples/ridley_resource.rb +2 -23
  48. data/spec/unit/ridley/bootstrap_bindings/unix_template_binding_spec.rb +3 -4
  49. data/spec/unit/ridley/bootstrap_bindings/windows_template_binding_spec.rb +3 -5
  50. data/spec/unit/ridley/bootstrapper/context_spec.rb +2 -3
  51. data/spec/unit/ridley/bootstrapper_spec.rb +1 -1
  52. data/spec/unit/ridley/chef_object_spec.rb +240 -0
  53. data/spec/unit/ridley/chef_objects/client_object_spec.rb +11 -0
  54. data/spec/unit/ridley/chef_objects/cookbook_object_spec.rb +93 -0
  55. data/spec/unit/ridley/chef_objects/data_bag_item_object_spec.rb +74 -0
  56. data/spec/unit/ridley/chef_objects/data_bag_object_spec.rb +9 -0
  57. data/spec/unit/ridley/chef_objects/environment_object_spec.rb +57 -0
  58. data/spec/unit/ridley/chef_objects/node_object_spec.rb +252 -0
  59. data/spec/unit/ridley/chef_objects/role_object_spec.rb +57 -0
  60. data/spec/unit/ridley/chef_objects/sandbox_object_spec.rb +66 -0
  61. data/spec/unit/ridley/client_spec.rb +51 -51
  62. data/spec/unit/ridley/host_connector/ssh/worker_spec.rb +4 -4
  63. data/spec/unit/ridley/host_connector/ssh_spec.rb +26 -24
  64. data/spec/unit/ridley/host_connector/winrm/worker_spec.rb +3 -4
  65. data/spec/unit/ridley/host_connector/winrm_spec.rb +4 -4
  66. data/spec/unit/ridley/host_connector_spec.rb +40 -3
  67. data/spec/unit/ridley/mixin/bootstrap_binding_spec.rb +1 -1
  68. data/spec/unit/ridley/resource_spec.rb +81 -109
  69. data/spec/unit/ridley/resources/client_resource_spec.rb +18 -33
  70. data/spec/unit/ridley/resources/cookbook_resource_spec.rb +56 -230
  71. data/spec/unit/ridley/resources/data_bag_item_resource_spec.rb +2 -57
  72. data/spec/unit/ridley/resources/data_bag_resource_spec.rb +12 -7
  73. data/spec/unit/ridley/resources/environment_resource_spec.rb +10 -118
  74. data/spec/unit/ridley/resources/node_resource_spec.rb +83 -394
  75. data/spec/unit/ridley/resources/role_resource_spec.rb +2 -56
  76. data/spec/unit/ridley/resources/sandbox_resource_spec.rb +139 -136
  77. data/spec/unit/ridley/resources/search_resource_spec.rb +234 -0
  78. data/spec/unit/ridley/sandbox_uploader_spec.rb +13 -58
  79. metadata +36 -17
  80. data/lib/ridley/chef/chefignore.rb +0 -76
  81. data/lib/ridley/resources/encrypted_data_bag_item_resource.rb +0 -55
  82. data/lib/ridley/resources/search.rb +0 -101
  83. data/spec/fixtures/chefignore +0 -8
  84. data/spec/unit/ridley/chef/chefignore_spec.rb +0 -40
  85. data/spec/unit/ridley/resources/search_spec.rb +0 -221
@@ -1,422 +1,222 @@
1
1
  module Ridley
2
2
  # @author Jamie Winsor <reset@riotgames.com>
3
3
  class CookbookResource < Ridley::Resource
4
- class << self
5
- # List all of the cookbooks and their versions present on the remote
6
- #
7
- # @example return value
8
- # {
9
- # "ant" => [
10
- # "0.10.1"
11
- # ],
12
- # "apache2" => [
13
- # "1.4.0"
14
- # ]
15
- # }
16
- #
17
- # @param [Ridley::Client] client
18
- #
19
- # @return [Hash]
20
- # a hash containing keys which represent cookbook names and values which contain
21
- # an array of strings representing the available versions
22
- def all(client)
23
- response = client.connection.get(self.resource_path).body
24
-
25
- {}.tap do |cookbooks|
26
- response.each do |name, details|
27
- cookbooks[name] = details["versions"].collect { |version| version["version"] }
28
- end
29
- end
30
- end
31
-
32
- # Delete a cookbook of the given name and version on the remote Chef server
33
- #
34
- # @param [Ridley::Client] client
35
- # @param [String] name
36
- # @param [String] version
37
- #
38
- # @option options [Boolean] purge (false)
39
- #
40
- # @return [Boolean]
41
- def delete(client, name, version, options = {})
42
- options = options.reverse_merge(purge: false)
43
- url = "#{self.resource_path}/#{name}/#{version}"
44
- url += "?purge=true" if options[:purge]
45
-
46
- client.connection.delete(url).body
47
- true
48
- rescue Errors::HTTPNotFound
49
- true
50
- end
51
-
52
- # Delete all of the versions of a given cookbook on the remote Chef server
53
- #
54
- # @param [Ridley::Client] client
55
- # @param [String] name
56
- # name of the cookbook to delete
57
- #
58
- # @option options [Boolean] purge (false)
59
- def delete_all(client, name, options = {})
60
- versions(client, name).each do |version|
61
- delete(client, name, version, options)
62
- end
63
- end
64
-
65
- # Download the entire cookbook
66
- #
67
- # @param [Ridley::Client] client
68
- # @param [String] name
69
- # @param [String] version
70
- # @param [String] destination (Dir.mktmpdir)
71
- # the place to download the cookbook too. If no value is provided the cookbook
72
- # will be downloaded to a temporary location
73
- #
74
- # @return [String]
75
- # the path to the directory the cookbook was downloaded to
76
- def download(client, name, version, destination = Dir.mktmpdir)
77
- cookbook = find(client, name, version)
78
-
79
- unless cookbook.nil?
80
- cookbook.download(destination)
81
- end
82
- end
83
-
84
- # @param [Ridley::Client] client
85
- # @param [String, #chef_id] object
86
- # @param [String] version
87
- #
88
- # @return [nil, CookbookResource]
89
- def find(client, object, version)
90
- find!(client, object, version)
91
- rescue Errors::HTTPNotFound
92
- nil
93
- end
94
-
95
- # @param [Ridley::Client] client
96
- # @param [String, #chef_id] object
97
- # @param [String] version
98
- #
99
- # @raise [Errors::HTTPNotFound]
100
- # if a resource with the given chef_id is not found
101
- #
102
- # @return [CookbookResource]
103
- def find!(client, object, version)
104
- chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
105
- new(client, client.connection.get("#{self.resource_path}/#{chef_id}/#{version}").body)
106
- end
107
-
108
- # Return the latest version of the given cookbook found on the remote Chef server
109
- #
110
- # @param [Ridley::Client] client
111
- # @param [String] name
112
- #
113
- # @return [String, nil]
114
- def latest_version(client, name)
115
- ver = versions(client, name).collect do |version|
116
- Solve::Version.new(version)
117
- end.sort.last
118
-
119
- ver.nil? ? nil : ver.to_s
120
- end
121
-
122
- # Return the version of the given cookbook which best stasifies the given constraint
123
- #
124
- # @param [Ridley::Client] client
125
- # @param [String] name
126
- # name of the cookbook
127
- # @param [String, Solve::Constraint] constraint
128
- # constraint to solve for
129
- #
130
- # @return [CookbookResource, nil]
131
- # returns the cookbook resource for the best solution or nil if no solution exists
132
- def satisfy(client, name, constraint)
133
- version = Solve::Solver.satisfy_best(constraint, versions(client, name)).to_s
134
- find(client, name, version)
135
- rescue Solve::Errors::NoSolutionError
136
- nil
137
- end
138
-
139
- # Update or create a new Cookbook Version of the given name, version with the
140
- # given manifest of files and checksums.
141
- #
142
- # @param [Ridley::Client] client
143
- # @param [Ridley::Chef::Cookbook] cookbook
144
- # the cookbook to save
145
- #
146
- # @option options [Boolean] :force
147
- # Upload the Cookbook even if the version already exists and is frozen on
148
- # the target Chef Server
149
- # @option options [Boolean] :freeze
150
- # Freeze the uploaded Cookbook on the Chef Server so that it cannot be
151
- # overwritten
152
- #
153
- # @raise [Ridley::Errors::FrozenCookbook]
154
- # if a cookbook of the same name and version already exists on the remote Chef server
155
- # and is frozen. If the :force option is provided the given cookbook will be saved
156
- # regardless.
157
- #
158
- # @return [Hash]
159
- def update(client, cookbook, options = {})
160
- options.reverse_merge(force: false, freeze: false)
161
-
162
- cookbook.frozen = options[:freeze]
163
-
164
- url = "cookbooks/#{cookbook.cookbook_name}/#{cookbook.version}"
165
- url << "?force=true" if options[:force]
166
-
167
- client.connection.put(url, cookbook.to_json)
168
- rescue Ridley::Errors::HTTPConflict => ex
169
- raise Ridley::Errors::FrozenCookbook, ex
170
- end
171
- alias_method :create, :update
172
-
173
- # Uploads a cookbook to the remote Chef server from the contents of a filepath
174
- #
175
- # @param [Ridley::Client] client
176
- # @param [String] path
177
- # path to a cookbook on local disk
178
- #
179
- # @option options [String] :name
180
- # automatically populated by the metadata of the cookbook at the given path, but
181
- # in the event that the metadata does not contain a name it can be specified with
182
- # this option
183
- # @option options [Boolean] :force (false)
184
- # Upload the Cookbook even if the version already exists and is frozen on
185
- # the target Chef Server
186
- # @option options [Boolean] :freeze (false)
187
- # Freeze the uploaded Cookbook on the Chef Server so that it cannot be
188
- # overwritten
189
- # @option options [Boolean] :validate (true)
190
- # Validate the contents of the cookbook before uploading
191
- #
192
- # @return [Hash]
193
- def upload(client, path, options = {})
194
- options = options.reverse_merge(validate: true, force: false, freeze: false)
195
- cookbook = Ridley::Chef::Cookbook.from_path(path, options.slice(:name))
196
-
197
- unless (existing = find(client, cookbook.cookbook_name, cookbook.version)).nil?
198
- if existing.frozen? && options[:force] == false
199
- msg = "The cookbook #{cookbook.cookbook_name} (#{cookbook.version}) already exists and is"
200
- msg << " frozen on the Chef server. Use the 'force' option to override."
201
- raise Ridley::Errors::FrozenCookbook, msg
202
- end
203
- end
204
-
205
- if options[:validate]
206
- cookbook.validate
207
- end
208
-
209
- checksums = cookbook.checksums.dup
210
- sandbox = client.sandbox.create(checksums.keys)
211
-
212
- sandbox.upload(checksums)
213
- sandbox.commit
214
- update(client, cookbook, options.slice(:force, :freeze))
215
- end
4
+ set_resource_path "cookbooks"
5
+ represented_by Ridley::CookbookObject
216
6
 
217
- # Return a list of versions for the given cookbook present on the remote Chef server
218
- #
219
- # @param [Ridley::Client] client
220
- # @param [String] name
221
- #
222
- # @example
223
- # versions(client, "nginx") => [ "1.0.0", "1.2.0" ]
224
- #
225
- # @return [Array<String>]
226
- def versions(client, name)
227
- response = client.connection.get("#{self.resource_path}/#{name}").body
7
+ def initialize(connection_registry, client_name, client_key, options = {})
8
+ super(connection_registry)
9
+ # @sandbox_resource = SandboxResource.new_link(connection_registry, client_name, client_key, options)
10
+ end
228
11
 
229
- response[name]["versions"].collect do |cb_ver|
230
- cb_ver["version"]
12
+ # List all of the cookbooks and their versions present on the remote
13
+ #
14
+ # @example return value
15
+ # {
16
+ # "ant" => [
17
+ # "0.10.1"
18
+ # ],
19
+ # "apache2" => [
20
+ # "1.4.0"
21
+ # ]
22
+ # }
23
+ #
24
+ # @return [Hash]
25
+ # a hash containing keys which represent cookbook names and values which contain
26
+ # an array of strings representing the available versions
27
+ def all
28
+ response = connection.get(self.class.resource_path).body
29
+
30
+ {}.tap do |cookbooks|
31
+ response.each do |name, details|
32
+ cookbooks[name] = details["versions"].collect { |version| version["version"] }
231
33
  end
232
34
  end
233
35
  end
234
36
 
235
- include Ridley::Logging
236
-
237
- FILE_TYPES = [
238
- :resources,
239
- :providers,
240
- :recipes,
241
- :definitions,
242
- :libraries,
243
- :attributes,
244
- :files,
245
- :templates,
246
- :root_files
247
- ].freeze
248
-
249
- set_chef_id "name"
250
- set_chef_type "cookbook"
251
- set_chef_json_class "Chef::Cookbook"
252
- set_resource_path "cookbooks"
253
-
254
- attribute :name,
255
- required: true
256
-
257
- attribute :attributes,
258
- type: Array,
259
- default: Array.new
260
-
261
- attribute :cookbook_name,
262
- type: String
263
-
264
- attribute :definitions,
265
- type: Array,
266
- default: Array.new
267
-
268
- attribute :files,
269
- type: Array,
270
- default: Array.new
271
-
272
- attribute :libraries,
273
- type: Array,
274
- default: Array.new
275
-
276
- attribute :metadata,
277
- type: Hashie::Mash
278
-
279
- attribute :providers,
280
- type: Array,
281
- default: Array.new
282
-
283
- attribute :recipes,
284
- type: Array,
285
- default: Array.new
286
-
287
- attribute :resources,
288
- type: Array,
289
- default: Array.new
290
-
291
- attribute :root_files,
292
- type: Array,
293
- default: Array.new
294
-
295
- attribute :templates,
296
- type: Array,
297
- default: Array.new
298
-
299
- attribute :version,
300
- type: String
37
+ # Delete a cookbook of the given name and version on the remote Chef server
38
+ #
39
+ # @param [String] name
40
+ # @param [String] version
41
+ #
42
+ # @option options [Boolean] purge (false)
43
+ #
44
+ # @return [Boolean]
45
+ def delete(name, version, options = {})
46
+ options = options.reverse_merge(purge: false)
47
+ url = "#{self.class.resource_path}/#{name}/#{version}"
48
+ url += "?purge=true" if options[:purge]
49
+
50
+ connection.delete(url).body
51
+ true
52
+ rescue Errors::HTTPNotFound
53
+ true
54
+ end
301
55
 
302
- attribute :frozen?,
303
- type: Boolean
56
+ # Delete all of the versions of a given cookbook on the remote Chef server
57
+ #
58
+ # @param [String] name
59
+ # name of the cookbook to delete
60
+ #
61
+ # @option options [Boolean] purge (false)
62
+ def delete_all(name, options = {})
63
+ versions(name).each do |version|
64
+ future(:delete, name, version, options)
65
+ end.map(&:value)
66
+ end
304
67
 
305
68
  # Download the entire cookbook
306
69
  #
70
+ # @param [String] name
71
+ # @param [String] version
307
72
  # @param [String] destination (Dir.mktmpdir)
308
73
  # the place to download the cookbook too. If no value is provided the cookbook
309
74
  # will be downloaded to a temporary location
310
75
  #
311
76
  # @return [String]
312
77
  # the path to the directory the cookbook was downloaded to
313
- def download(destination = Dir.mktmpdir)
314
- destination = File.expand_path(destination)
315
- log.debug { "downloading cookbook: '#{name}'" }
316
-
317
- FILE_TYPES.each do |filetype|
318
- next unless manifest.has_key?(filetype)
78
+ def download(name, version, destination = Dir.mktmpdir)
79
+ cookbook = find(name, version)
319
80
 
320
- manifest[filetype].each do |file|
321
- file_destination = File.join(destination, file[:path].gsub('/', File::SEPARATOR))
322
- FileUtils.mkdir_p(File.dirname(file_destination))
323
- download_file(filetype, file[:path], file_destination)
324
- end
81
+ unless cookbook.nil?
82
+ cookbook.download(destination)
325
83
  end
84
+ end
326
85
 
327
- destination
86
+ # @param [String, #chef_id] object
87
+ # @param [String] version
88
+ #
89
+ # @return [nil, CookbookResource]
90
+ def find(object, version)
91
+ chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
92
+ new(connection.get("#{self.class.resource_path}/#{chef_id}/#{version}").body)
93
+ rescue Errors::HTTPNotFound
94
+ nil
328
95
  end
329
96
 
330
- # Download a single file from a cookbook
97
+ # Return the latest version of the given cookbook found on the remote Chef server
331
98
  #
332
- # @param [#to_sym] filetype
333
- # the type of file to download. These are broken up into the following types in Chef:
334
- # - attribute (unsupported until resolved https://github.com/reset/chozo/issues/17)
335
- # - definition
336
- # - file
337
- # - library
338
- # - provider
339
- # - recipe
340
- # - resource
341
- # - root_file
342
- # - template
343
- # these types are where the files are stored in your cookbook's structure. For example, a
344
- # recipe would be stored in the recipes directory while a root_file is stored at the root
345
- # of your cookbook
346
- # @param [String] path
347
- # path of the file to download
348
- # @param [String] destination
349
- # where to download the file to
99
+ # @param [String] name
350
100
  #
351
- # @return [nil]
352
- def download_file(filetype, path, destination)
353
- download_fun(filetype).call(path, destination)
101
+ # @return [String, nil]
102
+ def latest_version(name)
103
+ ver = versions(name).collect do |version|
104
+ Solve::Version.new(version)
105
+ end.sort.last
106
+
107
+ ver.nil? ? nil : ver.to_s
354
108
  end
355
109
 
356
- # A hash containing keys for all of the different cookbook filetypes with values
357
- # representing each file of that type this cookbook contains
110
+ # Return the version of the given cookbook which best stasifies the given constraint
358
111
  #
359
- # @example
360
- # {
361
- # root_files: [
362
- # {
363
- # :name => "afile.rb",
364
- # :path => "files/ubuntu-9.10/afile.rb",
365
- # :checksum => "2222",
366
- # :specificity => "ubuntu-9.10"
367
- # },
368
- # ],
369
- # templates: [ manifest_record1, ... ],
370
- # ...
371
- # }
112
+ # @param [String] name
113
+ # name of the cookbook
114
+ # @param [String, Solve::Constraint] constraint
115
+ # constraint to solve for
372
116
  #
373
- # @return [Hash]
374
- def manifest
375
- {}.tap do |manifest|
376
- FILE_TYPES.each do |filetype|
377
- manifest[filetype] = get_attribute(filetype)
378
- end
379
- end
117
+ # @return [CookbookResource, nil]
118
+ # returns the cookbook resource for the best solution or nil if no solution exists
119
+ def satisfy(name, constraint)
120
+ version = Solve::Solver.satisfy_best(constraint, versions(name)).to_s
121
+ find(name, version)
122
+ rescue Solve::Errors::NoSolutionError
123
+ nil
380
124
  end
381
125
 
382
- def to_s
383
- "#{name}: #{manifest}"
384
- end
126
+ # Update or create a new Cookbook Version of the given name, version with the
127
+ # given manifest of files and checksums.
128
+ #
129
+ # @param [Ridley::Chef::Cookbook] cookbook
130
+ # the cookbook to save
131
+ #
132
+ # @option options [Boolean] :force
133
+ # Upload the Cookbook even if the version already exists and is frozen on
134
+ # the target Chef Server
135
+ # @option options [Boolean] :freeze
136
+ # Freeze the uploaded Cookbook on the Chef Server so that it cannot be
137
+ # overwritten
138
+ #
139
+ # @raise [Ridley::Errors::FrozenCookbook]
140
+ # if a cookbook of the same name and version already exists on the remote Chef server
141
+ # and is frozen. If the :force option is provided the given cookbook will be saved
142
+ # regardless.
143
+ #
144
+ # @return [Hash]
145
+ def update(cookbook, options = {})
146
+ options.reverse_merge(force: false, freeze: false)
385
147
 
386
- private
148
+ cookbook.frozen = options[:freeze]
149
+
150
+ url = "cookbooks/#{cookbook.cookbook_name}/#{cookbook.version}"
151
+ url << "?force=true" if options[:force]
387
152
 
388
- # Return a lambda for downloading a file from the cookbook of the given type
389
- #
390
- # @param [#to_sym] filetype
391
- #
392
- # @return [lambda]
393
- # a lambda which takes to parameters: target and path. Target is the URL to download from
394
- # and path is the location on disk to steam the contents of the remote URL to.
395
- def download_fun(filetype)
396
- collection = case filetype.to_sym
397
- when :attribute, :attributes; method(:attributes)
398
- when :definition, :definitions; method(:definitions)
399
- when :file, :files; method(:files)
400
- when :library, :libraries; method(:libraries)
401
- when :provider, :providers; method(:providers)
402
- when :recipe, :recipes; method(:recipes)
403
- when :resource, :resources; method(:resources)
404
- when :root_file, :root_files; method(:root_files)
405
- when :template, :templates; method(:templates)
406
- else
407
- raise Errors::UnknownCookbookFileType.new(filetype)
153
+ connection.put(url, cookbook.to_json)
154
+ rescue Ridley::Errors::HTTPConflict => ex
155
+ abort Ridley::Errors::FrozenCookbook.new(ex)
156
+ end
157
+ alias_method :create, :update
158
+
159
+ # Uploads a cookbook to the remote Chef server from the contents of a filepath
160
+ #
161
+ # @param [String] path
162
+ # path to a cookbook on local disk
163
+ #
164
+ # @option options [String] :name
165
+ # automatically populated by the metadata of the cookbook at the given path, but
166
+ # in the event that the metadata does not contain a name it can be specified with
167
+ # this option
168
+ # @option options [Boolean] :force (false)
169
+ # Upload the Cookbook even if the version already exists and is frozen on
170
+ # the target Chef Server
171
+ # @option options [Boolean] :freeze (false)
172
+ # Freeze the uploaded Cookbook on the Chef Server so that it cannot be
173
+ # overwritten
174
+ # @option options [Boolean] :validate (true)
175
+ # Validate the contents of the cookbook before uploading
176
+ #
177
+ # @return [Hash]
178
+ def upload(path, options = {})
179
+ options = options.reverse_merge(validate: true, force: false, freeze: false)
180
+ cookbook = Ridley::Chef::Cookbook.from_path(path, options.slice(:name))
181
+
182
+ unless (existing = find(cookbook.cookbook_name, cookbook.version)).nil?
183
+ if existing.frozen? && options[:force] == false
184
+ msg = "The cookbook #{cookbook.cookbook_name} (#{cookbook.version}) already exists and is"
185
+ msg << " frozen on the Chef server. Use the 'force' option to override."
186
+ abort Ridley::Errors::FrozenCookbook.new(msg)
408
187
  end
188
+ end
189
+
190
+ if options[:validate]
191
+ cookbook.validate
192
+ end
409
193
 
410
- ->(target, destination) {
411
- files = collection.call # JW: always chaining .call.find results in a nil value. WHY?
412
- file = files.find { |f| f[:path] == target }
413
- return nil if file.nil?
194
+ checksums = cookbook.checksums.dup
195
+ sandbox = sandbox_resource.create(checksums.keys)
414
196
 
415
- destination = File.expand_path(destination)
416
- log.debug { "downloading '#{filetype}' file: #{file} to: '#{destination}'" }
197
+ sandbox.upload(checksums)
198
+ sandbox.commit
199
+ update(cookbook, options.slice(:force, :freeze))
200
+ end
417
201
 
418
- client.connection.stream(file[:url], destination)
419
- }
202
+ # Return a list of versions for the given cookbook present on the remote Chef server
203
+ #
204
+ # @param [String] name
205
+ #
206
+ # @example
207
+ # versions("nginx") => [ "1.0.0", "1.2.0" ]
208
+ #
209
+ # @return [Array<String>]
210
+ def versions(name)
211
+ response = connection.get("#{self.class.resource_path}/#{name}").body
212
+
213
+ response[name]["versions"].collect do |cb_ver|
214
+ cb_ver["version"]
420
215
  end
216
+ end
217
+
218
+ private
219
+
220
+ attr_reader :sandbox_resource
421
221
  end
422
222
  end