ridley 0.11.0.rc1 → 0.11.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|