ridley 0.11.0.rc1 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +3 -2
- data/Gemfile +1 -0
- data/Guardfile +2 -2
- data/Thorfile +2 -2
- data/lib/ridley/chef.rb +1 -0
- data/lib/ridley/chef/chefignore.rb +76 -0
- data/lib/ridley/chef/cookbook.rb +17 -7
- data/lib/ridley/chef/cookbook/metadata.rb +8 -0
- data/lib/ridley/chef_objects/cookbook_object.rb +21 -37
- data/lib/ridley/chef_objects/data_bag_item_obect.rb +9 -0
- data/lib/ridley/client.rb +2 -2
- data/lib/ridley/connection.rb +12 -6
- data/lib/ridley/errors.rb +14 -0
- data/lib/ridley/host_connector.rb +10 -3
- data/lib/ridley/resource.rb +25 -5
- data/lib/ridley/resources/cookbook_resource.rb +19 -9
- data/lib/ridley/resources/data_bag_item_resource.rb +8 -4
- data/lib/ridley/resources/search_resource.rb +5 -5
- data/lib/ridley/sandbox_uploader.rb +6 -0
- data/lib/ridley/version.rb +1 -1
- data/ridley.gemspec +1 -1
- data/spec/acceptance/client_resource_spec.rb +44 -62
- data/spec/acceptance/cookbook_resource_spec.rb +27 -0
- data/spec/acceptance/data_bag_item_resource_spec.rb +36 -54
- data/spec/acceptance/data_bag_resource_spec.rb +9 -21
- data/spec/acceptance/environment_resource_spec.rb +34 -63
- data/spec/acceptance/node_resource_spec.rb +27 -47
- data/spec/acceptance/role_resource_spec.rb +27 -67
- data/spec/acceptance/sandbox_resource_spec.rb +3 -13
- data/spec/acceptance/search_resource_spec.rb +5 -15
- data/spec/fixtures/chefignore +8 -0
- data/spec/spec_helper.rb +15 -1
- data/spec/support/chef_server.rb +77 -0
- data/spec/unit/ridley/chef/chefignore_spec.rb +40 -0
- data/spec/unit/ridley/chef/cookbook_spec.rb +30 -2
- data/spec/unit/ridley/chef_objects/cookbook_object_spec.rb +3 -3
- data/spec/unit/ridley/connection_spec.rb +1 -2
- data/spec/unit/ridley/resources/cookbook_resource_spec.rb +85 -48
- data/spec/unit/ridley/resources/data_bag_resource_spec.rb +1 -1
- data/spec/unit/ridley/resources/search_resource_spec.rb +39 -2
- data/spec/unit/ridley/sandbox_uploader_spec.rb +25 -0
- metadata +19 -7
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Guardfile
CHANGED
@@ -12,10 +12,10 @@ guard 'yard', stdout: '/dev/null', stderr: '/dev/null' do
|
|
12
12
|
watch(%r{ext/.+\.c})
|
13
13
|
end
|
14
14
|
|
15
|
-
guard 'rspec', cli: "--color --drb --format Fuubar
|
15
|
+
guard 'rspec', cli: "--color --drb --format Fuubar", all_on_start: false, all_after_pass: false do
|
16
16
|
watch(%r{^spec/unit/.+_spec\.rb$})
|
17
17
|
watch(%r{^spec/acceptance/.+_spec\.rb$})
|
18
|
-
|
18
|
+
|
19
19
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
|
20
20
|
watch('spec/spec_helper.rb') { "spec" }
|
21
21
|
watch(%r{^spec/support/.+\.rb$}) { "spec" }
|
data/Thorfile
CHANGED
@@ -9,7 +9,7 @@ require 'ridley'
|
|
9
9
|
class Default < Thor
|
10
10
|
unless jruby?
|
11
11
|
require 'thor/rake_compat'
|
12
|
-
|
12
|
+
|
13
13
|
include Thor::RakeCompat
|
14
14
|
Bundler::GemHelper.install_tasks
|
15
15
|
|
@@ -40,7 +40,7 @@ class Default < Thor
|
|
40
40
|
|
41
41
|
desc "unit", "run only unit tests"
|
42
42
|
def unit
|
43
|
-
exec "rspec --color --format=documentation spec --tag ~type:acceptance"
|
43
|
+
exec "rspec --color --format=documentation spec --tag ~type:acceptance"
|
44
44
|
end
|
45
45
|
|
46
46
|
desc "acceptance", "run only acceptance tests"
|
data/lib/ridley/chef.rb
CHANGED
@@ -0,0 +1,76 @@
|
|
1
|
+
module Ridley::Chef
|
2
|
+
# Borrowed and modified from:
|
3
|
+
# {https://raw.github.com/opscode/chef/62f9b0e3be8e22eef092163c331b7d3f8d350f94/lib/chef/cookbook/chefignore.rb}
|
4
|
+
#
|
5
|
+
# Copyright:: Copyright (c) 2011 Opscode, Inc.
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
class Chefignore
|
19
|
+
class << self
|
20
|
+
# Traverse a path in relative context to find a Chefignore file
|
21
|
+
#
|
22
|
+
# @param [String] path
|
23
|
+
# path to traverse
|
24
|
+
#
|
25
|
+
# @return [String, nil]
|
26
|
+
def find_relative_to(path)
|
27
|
+
[
|
28
|
+
File.join(path, FILENAME),
|
29
|
+
File.join(path, 'cookbooks', FILENAME)
|
30
|
+
].find { |f| File.exists?(f) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
FILENAME = "chefignore".freeze
|
35
|
+
COMMENTS_AND_WHITESPACE = /^\s*(?:#.*)?$/
|
36
|
+
|
37
|
+
attr_reader :ignores
|
38
|
+
|
39
|
+
def initialize(ignore_file_or_repo)
|
40
|
+
@ignore_file = find_ignore_file(ignore_file_or_repo)
|
41
|
+
@ignores = parse_ignore_file
|
42
|
+
end
|
43
|
+
|
44
|
+
def remove_ignores_from(file_list)
|
45
|
+
Array(file_list).inject([]) do |unignored, file|
|
46
|
+
ignored?(file) ? unignored : unignored << file
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def ignored?(file_name)
|
51
|
+
@ignores.any? { |glob| File.fnmatch?(glob, file_name) }
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def parse_ignore_file
|
57
|
+
ignore_globs = []
|
58
|
+
|
59
|
+
if File.exist?(@ignore_file) && File.readable?(@ignore_file)
|
60
|
+
File.foreach(@ignore_file) do |line|
|
61
|
+
ignore_globs << line.strip unless line =~ COMMENTS_AND_WHITESPACE
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
ignore_globs
|
66
|
+
end
|
67
|
+
|
68
|
+
def find_ignore_file(path)
|
69
|
+
if File.basename(path) =~ /#{FILENAME}/
|
70
|
+
path
|
71
|
+
else
|
72
|
+
File.join(path, FILENAME)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/ridley/chef/cookbook.rb
CHANGED
@@ -29,20 +29,21 @@ module Ridley::Chef
|
|
29
29
|
# explicitly supply the name of the cookbook we are loading. This is useful if
|
30
30
|
# you are dealing with a cookbook that does not have well-formed metadata
|
31
31
|
#
|
32
|
-
# @raise [IOError] if the path does not contain a metadata.rb file
|
32
|
+
# @raise [IOError] if the path does not contain a metadata.rb or metadata.json file
|
33
33
|
#
|
34
34
|
# @return [Ridley::Chef::Cookbook]
|
35
35
|
def from_path(path, options = {})
|
36
36
|
path = Pathname.new(path)
|
37
|
-
metadata =
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
metadata = if path.join('metadata.rb').exist?
|
38
|
+
Cookbook::Metadata.from_file(path.join('metadata.rb'))
|
39
|
+
elsif path.join('metadata.json').exist?
|
40
|
+
Cookbook::Metadata.from_json(File.read(path.join('metadata.json')))
|
41
41
|
else
|
42
|
-
metadata.
|
42
|
+
raise IOError, "no metadata.rb or metadata.json found at #{path}"
|
43
43
|
end
|
44
44
|
|
45
|
-
|
45
|
+
metadata.name(options[:name].presence || metadata.name.presence || File.basename(path))
|
46
|
+
new(metadata.name, path, metadata)
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
@@ -96,6 +97,7 @@ module Ridley::Chef
|
|
96
97
|
root_files: Array.new
|
97
98
|
)
|
98
99
|
@frozen = false
|
100
|
+
@chefignore = Ridley::Chef::Chefignore.new(@path)
|
99
101
|
|
100
102
|
load_files
|
101
103
|
end
|
@@ -207,7 +209,12 @@ module Ridley::Chef
|
|
207
209
|
|
208
210
|
private
|
209
211
|
|
212
|
+
# @return [Array]
|
210
213
|
attr_reader :files
|
214
|
+
# @return [Ridley::Chef::Chefignore]
|
215
|
+
attr_reader :chefignore
|
216
|
+
|
217
|
+
def_delegator :chefignore, :ignored?
|
211
218
|
|
212
219
|
def load_files
|
213
220
|
load_shallow(:recipes, 'recipes', '*.rb')
|
@@ -225,6 +232,7 @@ module Ridley::Chef
|
|
225
232
|
[].tap do |files|
|
226
233
|
Dir.glob(path.join('*'), File::FNM_DOTMATCH).each do |file|
|
227
234
|
next if File.directory?(file)
|
235
|
+
next if ignored?(file)
|
228
236
|
@files << file
|
229
237
|
@manifest[:root_files] << file_metadata(:root_files, file)
|
230
238
|
end
|
@@ -236,6 +244,7 @@ module Ridley::Chef
|
|
236
244
|
file_spec = path.join(category_dir, '**', glob)
|
237
245
|
Dir.glob(file_spec, File::FNM_DOTMATCH).each do |file|
|
238
246
|
next if File.directory?(file)
|
247
|
+
next if ignored?(file)
|
239
248
|
@files << file
|
240
249
|
@manifest[category] << file_metadata(category, file)
|
241
250
|
end
|
@@ -245,6 +254,7 @@ module Ridley::Chef
|
|
245
254
|
def load_shallow(category, *path_glob)
|
246
255
|
[].tap do |files|
|
247
256
|
Dir[path.join(*path_glob)].each do |file|
|
257
|
+
next if ignored?(file)
|
248
258
|
@files << file
|
249
259
|
@manifest[category] << file_metadata(category, file)
|
250
260
|
end
|
@@ -26,6 +26,10 @@ module Ridley::Chef
|
|
26
26
|
def from_hash(hash)
|
27
27
|
new.from_hash(hash)
|
28
28
|
end
|
29
|
+
|
30
|
+
def from_json(json)
|
31
|
+
new.from_json(json)
|
32
|
+
end
|
29
33
|
end
|
30
34
|
|
31
35
|
NAME = 'name'.freeze
|
@@ -458,6 +462,10 @@ module Ridley::Chef
|
|
458
462
|
self
|
459
463
|
end
|
460
464
|
|
465
|
+
def from_json(json)
|
466
|
+
from_hash MultiJson.decode(json)
|
467
|
+
end
|
468
|
+
|
461
469
|
private
|
462
470
|
|
463
471
|
# Verify that the given array is an array of strings
|
@@ -118,7 +118,27 @@ module Ridley
|
|
118
118
|
#
|
119
119
|
# @return [nil]
|
120
120
|
def download_file(filetype, path, destination)
|
121
|
-
|
121
|
+
files = case filetype.to_sym
|
122
|
+
when :attribute, :attributes; attributes
|
123
|
+
when :definition, :definitions; definitions
|
124
|
+
when :file, :files; files
|
125
|
+
when :library, :libraries; libraries
|
126
|
+
when :provider, :providers; providers
|
127
|
+
when :recipe, :recipes; recipes
|
128
|
+
when :resource, :resources; resources
|
129
|
+
when :root_file, :root_files; root_files
|
130
|
+
when :template, :templates; templates
|
131
|
+
else
|
132
|
+
raise Errors::UnknownCookbookFileType.new(filetype)
|
133
|
+
end
|
134
|
+
|
135
|
+
file = files.find { |f| f[:path] == path }
|
136
|
+
return nil if file.nil?
|
137
|
+
|
138
|
+
destination = File.expand_path(destination)
|
139
|
+
log.debug { "downloading '#{filetype}' file: #{file} to: '#{destination}'" }
|
140
|
+
|
141
|
+
resource.connection.stream(file[:url], destination)
|
122
142
|
end
|
123
143
|
|
124
144
|
# A hash containing keys for all of the different cookbook filetypes with values
|
@@ -150,41 +170,5 @@ module Ridley
|
|
150
170
|
def to_s
|
151
171
|
"#{name}: #{manifest}"
|
152
172
|
end
|
153
|
-
|
154
|
-
private
|
155
|
-
|
156
|
-
# Return a lambda for downloading a file from the cookbook of the given type
|
157
|
-
#
|
158
|
-
# @param [#to_sym] filetype
|
159
|
-
#
|
160
|
-
# @return [lambda]
|
161
|
-
# a lambda which takes to parameters: target and path. Target is the URL to download from
|
162
|
-
# and path is the location on disk to steam the contents of the remote URL to.
|
163
|
-
def download_fun(filetype)
|
164
|
-
collection = case filetype.to_sym
|
165
|
-
when :attribute, :attributes; method(:attributes)
|
166
|
-
when :definition, :definitions; method(:definitions)
|
167
|
-
when :file, :files; method(:files)
|
168
|
-
when :library, :libraries; method(:libraries)
|
169
|
-
when :provider, :providers; method(:providers)
|
170
|
-
when :recipe, :recipes; method(:recipes)
|
171
|
-
when :resource, :resources; method(:resources)
|
172
|
-
when :root_file, :root_files; method(:root_files)
|
173
|
-
when :template, :templates; method(:templates)
|
174
|
-
else
|
175
|
-
raise Errors::UnknownCookbookFileType.new(filetype)
|
176
|
-
end
|
177
|
-
|
178
|
-
->(target, destination) {
|
179
|
-
files = collection.call # JW: always chaining .call.find results in a nil value. WHY?
|
180
|
-
file = files.find { |f| f[:path] == target }
|
181
|
-
return nil if file.nil?
|
182
|
-
|
183
|
-
destination = File.expand_path(destination)
|
184
|
-
log.debug { "downloading '#{filetype}' file: #{file} to: '#{destination}'" }
|
185
|
-
|
186
|
-
connection.stream(file[:url], destination)
|
187
|
-
}
|
188
|
-
end
|
189
173
|
end
|
190
174
|
end
|
@@ -48,6 +48,15 @@ module Ridley
|
|
48
48
|
mass_assign(decrypted_hash)
|
49
49
|
end
|
50
50
|
|
51
|
+
# Decrypts an individual value stored inside the data bag item.
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# data_bag_item.decrypt_value("Xk0E8lV9r4BhZzcg4wal0X4w9ZexN3azxMjZ9r1MCZc=")
|
55
|
+
# => {test: {database: {username: "test"}}}
|
56
|
+
#
|
57
|
+
# @param [String] an encrypted String value
|
58
|
+
#
|
59
|
+
# @return [Hash] a decrypted attribute value
|
51
60
|
def decrypt_value(value)
|
52
61
|
if encrypted_data_bag_secret.nil?
|
53
62
|
raise Errors::EncryptedDataBagSecretNotSet
|
data/lib/ridley/client.rb
CHANGED
@@ -234,7 +234,7 @@ module Ridley
|
|
234
234
|
#
|
235
235
|
# @return [Hash]
|
236
236
|
def search(index, query = nil, options = {})
|
237
|
-
@resources_registry[:search_resource].run(index, query, options)
|
237
|
+
@resources_registry[:search_resource].run(index, query, @resources_registry, options)
|
238
238
|
end
|
239
239
|
|
240
240
|
# Return the array of all possible search indexes for the including connection
|
@@ -257,7 +257,7 @@ module Ridley
|
|
257
257
|
def encrypted_data_bag_secret
|
258
258
|
return nil if encrypted_data_bag_secret_path.nil?
|
259
259
|
|
260
|
-
IO.read(encrypted_data_bag_secret_path).chomp
|
260
|
+
::IO.read(encrypted_data_bag_secret_path).chomp
|
261
261
|
rescue Errno::ENOENT => e
|
262
262
|
raise Errors::EncryptedDataBagSecretNotFound, "Encrypted data bag secret provided but not found at '#{encrypted_data_bag_secret_path}'"
|
263
263
|
end
|
data/lib/ridley/connection.rb
CHANGED
@@ -14,8 +14,11 @@ module Ridley
|
|
14
14
|
:proxy
|
15
15
|
]
|
16
16
|
|
17
|
+
# @return [String]
|
17
18
|
attr_reader :organization
|
19
|
+
# @return [String]
|
18
20
|
attr_reader :client_key
|
21
|
+
# @return [String]
|
19
22
|
attr_reader :client_name
|
20
23
|
# @return [Integer]
|
21
24
|
# how many retries to attempt on HTTP requests
|
@@ -95,7 +98,7 @@ module Ridley
|
|
95
98
|
# Override Faraday::Connection#run_request to catch exceptions from {Ridley::Middleware} that
|
96
99
|
# we expect. Caught exceptions are re-raised with Celluloid#abort so we don't crash the connection.
|
97
100
|
def run_request(*args)
|
98
|
-
super
|
101
|
+
defer { super }
|
99
102
|
rescue Errors::HTTPError, Faraday::Error => ex
|
100
103
|
abort(ex)
|
101
104
|
end
|
@@ -129,13 +132,16 @@ module Ridley
|
|
129
132
|
local = Tempfile.new('ridley-stream')
|
130
133
|
local.binmode
|
131
134
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
+
defer {
|
136
|
+
retryable(tries: retries, on: OpenURI::HTTPError, sleep: retry_interval) do
|
137
|
+
open(target, 'rb', headers) do |remote|
|
138
|
+
local.write(remote.read)
|
139
|
+
end
|
135
140
|
end
|
136
|
-
end
|
137
141
|
|
138
|
-
|
142
|
+
local.flush
|
143
|
+
}
|
144
|
+
|
139
145
|
FileUtils.mv(local.path, destination)
|
140
146
|
rescue OpenURI::HTTPError => ex
|
141
147
|
abort(ex)
|
data/lib/ridley/errors.rb
CHANGED
@@ -115,17 +115,31 @@ module Ridley
|
|
115
115
|
class HTTP5XXError < HTTPError; end
|
116
116
|
|
117
117
|
# 3XX
|
118
|
+
class HTTPMultipleChoices < HTTP3XXError; register_error(300); end
|
118
119
|
class HTTPMovedPermanently < HTTP3XXError; register_error(301); end
|
119
120
|
class HTTPFound < HTTP3XXError; register_error(302); end
|
121
|
+
class HTTPSeeOther < HTTP3XXError; register_error(303); end
|
122
|
+
class HTTPNotModified < HTTP3XXError; register_error(304); end
|
123
|
+
class HTTPUseProxy < HTTP3XXError; register_error(305); end
|
124
|
+
class HTTPTemporaryRedirect < HTTP3XXError; register_error(307); end
|
120
125
|
|
121
126
|
# 4XX
|
122
127
|
class HTTPBadRequest < HTTP4XXError; register_error(400); end
|
123
128
|
class HTTPUnauthorized < HTTP4XXError; register_error(401); end
|
129
|
+
class HTTPPaymentRequired < HTTP4XXError; register_error(402); end
|
124
130
|
class HTTPForbidden < HTTP4XXError; register_error(403); end
|
125
131
|
class HTTPNotFound < HTTP4XXError; register_error(404); end
|
126
132
|
class HTTPMethodNotAllowed < HTTP4XXError; register_error(405); end
|
133
|
+
class HTTPNotAcceptable < HTTP4XXError; register_error(406); end
|
134
|
+
class HTTPProxyAuthenticationRequired < HTTP4XXError; register_error(407); end
|
127
135
|
class HTTPRequestTimeout < HTTP4XXError; register_error(408); end
|
128
136
|
class HTTPConflict < HTTP4XXError; register_error(409); end
|
137
|
+
class HTTPGone < HTTP4XXError; register_error(410); end
|
138
|
+
class HTTPLengthRequired < HTTP4XXError; register_error(411); end
|
139
|
+
class HTTPPreconditionFailed < HTTP4XXError; register_error(412); end
|
140
|
+
class HTTPRequestEntityTooLarge < HTTP4XXError; register_error(413); end
|
141
|
+
class HTTPRequestURITooLong < HTTP4XXError; register_error(414); end
|
142
|
+
class HTTPUnsupportedMediaType < HTTP4XXError; register_error(415); end
|
129
143
|
|
130
144
|
# 5XX
|
131
145
|
class HTTPInternalServerError < HTTP5XXError; register_error(500); end
|
@@ -42,6 +42,7 @@ module Ridley
|
|
42
42
|
# the host to attempt to connect to
|
43
43
|
# @option options [Hash] :ssh
|
44
44
|
# * :port (Fixnum) the ssh port to connect on the node the bootstrap will be performed on (22)
|
45
|
+
# * :timeout (Float) [5.0] timeout value for testing SSH connection
|
45
46
|
# @option options [Hash] :winrm
|
46
47
|
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
|
47
48
|
# @param block [Proc]
|
@@ -50,7 +51,9 @@ module Ridley
|
|
50
51
|
# @return [Ridley::HostConnector] a class under Ridley::HostConnector
|
51
52
|
def best_connector_for(host, options = {}, &block)
|
52
53
|
ssh_port, winrm_port = parse_port_options(options)
|
53
|
-
|
54
|
+
timeout = options[:ssh] && options[:ssh][:timeout]
|
55
|
+
|
56
|
+
if connector_port_open?(host, ssh_port, timeout)
|
54
57
|
host_connector = Ridley::HostConnector::SSH
|
55
58
|
elsif connector_port_open?(host, winrm_port)
|
56
59
|
host_connector = Ridley::HostConnector::WinRM
|
@@ -72,10 +75,14 @@ module Ridley
|
|
72
75
|
# the host to attempt to connect to
|
73
76
|
# @param port [Fixnum]
|
74
77
|
# the port to attempt to connect on
|
78
|
+
# @param timeout [Float]
|
79
|
+
# the number of seconds to wait (default: 3)
|
75
80
|
#
|
76
81
|
# @return [Boolean]
|
77
|
-
def connector_port_open?(host, port)
|
78
|
-
|
82
|
+
def connector_port_open?(host, port, timeout = nil)
|
83
|
+
timeout ||= 3
|
84
|
+
|
85
|
+
Timeout::timeout(timeout) do
|
79
86
|
socket = TCPSocket.new(host, port)
|
80
87
|
socket.close
|
81
88
|
end
|