ridley 0.7.0.beta → 0.7.0.rc1
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/README.md +51 -54
- data/lib/ridley.rb +7 -13
- data/lib/ridley/client.rb +251 -0
- data/lib/ridley/connection.rb +32 -188
- data/lib/ridley/middleware/chef_auth.rb +4 -1
- data/lib/ridley/resource.rb +36 -42
- data/lib/ridley/resources.rb +3 -0
- data/lib/ridley/resources/{client.rb → client_resource.rb} +7 -20
- data/lib/ridley/resources/cookbook_resource.rb +121 -0
- data/lib/ridley/resources/{data_bag_item.rb → data_bag_item_resource.rb} +52 -63
- data/lib/ridley/resources/data_bag_resource.rb +74 -0
- data/lib/ridley/resources/encrypted_data_bag_item_resource.rb +55 -0
- data/lib/ridley/resources/{environment.rb → environment_resource.rb} +8 -21
- data/lib/ridley/resources/{node.rb → node_resource.rb} +24 -37
- data/lib/ridley/resources/{role.rb → role_resource.rb} +1 -14
- data/lib/ridley/resources/sandbox_resource.rb +86 -0
- data/lib/ridley/resources/search.rb +24 -55
- data/lib/ridley/sandbox_uploader.rb +118 -0
- data/lib/ridley/ssh.rb +2 -2
- data/lib/ridley/ssh/worker.rb +2 -1
- data/lib/ridley/version.rb +1 -1
- data/ridley.gemspec +1 -1
- data/spec/acceptance/bootstrapping_spec.rb +1 -1
- data/spec/acceptance/client_resource_spec.rb +18 -20
- data/spec/acceptance/cookbook_resource_spec.rb +4 -22
- data/spec/acceptance/data_bag_item_resource_spec.rb +5 -7
- data/spec/acceptance/data_bag_resource_spec.rb +4 -6
- data/spec/acceptance/environment_resource_spec.rb +14 -16
- data/spec/acceptance/node_resource_spec.rb +12 -14
- data/spec/acceptance/role_resource_spec.rb +13 -15
- data/spec/acceptance/sandbox_resource_spec.rb +7 -9
- data/spec/acceptance/search_resource_spec.rb +6 -8
- data/spec/support/shared_examples/ridley_resource.rb +23 -22
- data/spec/unit/ridley/client_spec.rb +153 -0
- data/spec/unit/ridley/connection_spec.rb +8 -221
- data/spec/unit/ridley/resources/{client_spec.rb → client_resource_spec.rb} +4 -4
- data/spec/unit/ridley/resources/cookbook_resource_spec.rb +5 -0
- data/spec/unit/ridley/resources/{data_bag_item_spec.rb → data_bag_item_resource_spec.rb} +2 -2
- data/spec/unit/ridley/resources/{data_bag_spec.rb → data_bag_resource_spec.rb} +3 -3
- data/spec/unit/ridley/resources/{environment_spec.rb → environment_resource_spec.rb} +4 -4
- data/spec/unit/ridley/resources/{node_spec.rb → node_resource_spec.rb} +4 -4
- data/spec/unit/ridley/resources/{role_spec.rb → role_resource_spec.rb} +3 -3
- data/spec/unit/ridley/resources/sandbox_resource_spec.rb +172 -0
- data/spec/unit/ridley/resources/search_spec.rb +34 -30
- data/spec/unit/ridley/sandbox_uploader_spec.rb +99 -0
- data/spec/unit/ridley/ssh_spec.rb +2 -2
- data/spec/unit/ridley_spec.rb +4 -12
- metadata +36 -28
- data/lib/ridley/dsl.rb +0 -58
- data/lib/ridley/resources/cookbook.rb +0 -51
- data/lib/ridley/resources/data_bag.rb +0 -81
- data/lib/ridley/resources/encrypted_data_bag_item.rb +0 -54
- data/lib/ridley/resources/sandbox.rb +0 -154
- data/spec/unit/ridley/resources/cookbook_spec.rb +0 -5
@@ -1,16 +1,16 @@
|
|
1
1
|
module Ridley
|
2
2
|
# @author Jamie Winsor <jamie@vialstudios.com>
|
3
|
-
class
|
3
|
+
class EnvironmentResource < Ridley::Resource
|
4
4
|
class << self
|
5
|
-
# Delete all of the environments on the
|
6
|
-
#
|
5
|
+
# Delete all of the environments on the client. The '_default' environment
|
6
|
+
# will never be deleted.
|
7
7
|
#
|
8
|
-
# @param [Ridley::
|
8
|
+
# @param [Ridley::Client] client
|
9
9
|
#
|
10
|
-
# @return [Array<Ridley::
|
11
|
-
def delete_all(
|
12
|
-
envs = all(
|
13
|
-
envs.collect { |obj| delete(
|
10
|
+
# @return [Array<Ridley::EnvironmentResource>]
|
11
|
+
def delete_all(client)
|
12
|
+
envs = all(client).reject { |env| env.name.to_s == '_default' }
|
13
|
+
envs.collect { |obj| delete(client, obj) }
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -70,17 +70,4 @@ module Ridley
|
|
70
70
|
self.override_attributes = self.override_attributes.deep_merge(attr_hash)
|
71
71
|
end
|
72
72
|
end
|
73
|
-
|
74
|
-
module DSL
|
75
|
-
# Coerces instance functions into class functions on Ridley::Environment. This coercion
|
76
|
-
# sends an instance of the including class along to the class function.
|
77
|
-
#
|
78
|
-
# @see Ridley::ChainLink
|
79
|
-
#
|
80
|
-
# @return [Ridley::ChainLink]
|
81
|
-
# a context object to delegate instance functions to class functions on Ridley::Environment
|
82
|
-
def environment
|
83
|
-
ChainLink.new(self, Ridley::Environment)
|
84
|
-
end
|
85
|
-
end
|
86
73
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Ridley
|
2
2
|
# @author Jamie Winsor <jamie@vialstudios.com>
|
3
|
-
class
|
3
|
+
class NodeResource < Ridley::Resource
|
4
4
|
class << self
|
5
|
-
# @overload bootstrap(
|
6
|
-
# @param [Ridley::
|
5
|
+
# @overload bootstrap(client, nodes, options = {})
|
6
|
+
# @param [Ridley::Client] client
|
7
7
|
# @param [Array<String>, String] nodes
|
8
8
|
# @param [Hash] ssh
|
9
9
|
# * :user (String) a shell user that will login to each node and perform the bootstrap command on (required)
|
@@ -33,15 +33,15 @@ module Ridley
|
|
33
33
|
# bootstrap template to use (default: omnibus)
|
34
34
|
#
|
35
35
|
# @return [SSH::ResponseSet]
|
36
|
-
def bootstrap(
|
36
|
+
def bootstrap(client, *args)
|
37
37
|
options = args.extract_options!
|
38
38
|
|
39
39
|
default_options = {
|
40
|
-
server_url:
|
41
|
-
validator_path:
|
42
|
-
validator_client:
|
43
|
-
encrypted_data_bag_secret_path:
|
44
|
-
ssh:
|
40
|
+
server_url: client.server_url,
|
41
|
+
validator_path: client.validator_path,
|
42
|
+
validator_client: client.validator_client,
|
43
|
+
encrypted_data_bag_secret_path: client.encrypted_data_bag_secret_path,
|
44
|
+
ssh: client.ssh
|
45
45
|
}
|
46
46
|
|
47
47
|
options = default_options.merge(options)
|
@@ -51,8 +51,8 @@ module Ridley
|
|
51
51
|
|
52
52
|
# Merges the given data with the the data of the target node on the remote
|
53
53
|
#
|
54
|
-
# @param [Ridley::
|
55
|
-
# @param [Ridley::
|
54
|
+
# @param [Ridley::Client] client
|
55
|
+
# @param [Ridley::NodeResource, String] target
|
56
56
|
# node or identifier of the node to merge
|
57
57
|
# @option options [Array] :run_list
|
58
58
|
# run list items to merge
|
@@ -62,9 +62,9 @@ module Ridley
|
|
62
62
|
# @raise [Errors::HTTPNotFound]
|
63
63
|
# if the target node is not found
|
64
64
|
#
|
65
|
-
# @return [Ridley::
|
66
|
-
def merge_data(
|
67
|
-
find!(
|
65
|
+
# @return [Ridley::NodeResource]
|
66
|
+
def merge_data(client, target, options = {})
|
67
|
+
find!(client, target).merge_data(options)
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -119,9 +119,9 @@ module Ridley
|
|
119
119
|
# @param [String] key
|
120
120
|
# @param [Object] value
|
121
121
|
#
|
122
|
-
# @return [
|
122
|
+
# @return [Hashie::Mash]
|
123
123
|
def set_chef_attribute(key, value)
|
124
|
-
attr_hash =
|
124
|
+
attr_hash = Hashie::Mash.from_dotted_path(key, value)
|
125
125
|
self.normal = self.normal.deep_merge(attr_hash)
|
126
126
|
end
|
127
127
|
|
@@ -197,7 +197,7 @@ module Ridley
|
|
197
197
|
#
|
198
198
|
# @return [SSH::Response]
|
199
199
|
def chef_client(options = {})
|
200
|
-
options =
|
200
|
+
options = client.ssh.merge(options)
|
201
201
|
|
202
202
|
Ridley.log.debug "Running Chef Client on: #{self.public_hostname}"
|
203
203
|
Ridley::SSH.start(self, options) do |ssh|
|
@@ -205,8 +205,8 @@ module Ridley
|
|
205
205
|
end
|
206
206
|
end
|
207
207
|
|
208
|
-
# Put the
|
209
|
-
# encrypted data bag key path is set on the resource's
|
208
|
+
# Put the client's encrypted data bag secret onto the instantiated node. If no
|
209
|
+
# encrypted data bag key path is set on the resource's client then nil will be
|
210
210
|
# returned
|
211
211
|
#
|
212
212
|
# @param [Hash] options
|
@@ -214,14 +214,14 @@ module Ridley
|
|
214
214
|
#
|
215
215
|
# @return [SSH::Response, nil]
|
216
216
|
def put_secret(options = {})
|
217
|
-
if
|
218
|
-
!File.exists?(
|
217
|
+
if client.encrypted_data_bag_secret_path.nil? ||
|
218
|
+
!File.exists?(client.encrypted_data_bag_secret_path)
|
219
219
|
|
220
220
|
return nil
|
221
221
|
end
|
222
222
|
|
223
|
-
options =
|
224
|
-
secret = File.read(
|
223
|
+
options = client.ssh.merge(options)
|
224
|
+
secret = File.read(client.encrypted_data_bag_secret_path).chomp
|
225
225
|
command = "echo '#{secret}' > /etc/chef/encrypted_data_bag_secret; chmod 0600 /etc/chef/encrypted_data_bag_secret"
|
226
226
|
|
227
227
|
Ridley.log.debug "Writing Encrypted Data Bag Secret to: #{self.public_hostname}"
|
@@ -238,7 +238,7 @@ module Ridley
|
|
238
238
|
# @option options [Hash] :attributes
|
239
239
|
# attributes of normal precedence to merge
|
240
240
|
#
|
241
|
-
# @return [Ridley::
|
241
|
+
# @return [Ridley::NodeResource]
|
242
242
|
def merge_data(options = {})
|
243
243
|
unless options[:run_list].nil?
|
244
244
|
self.run_list = (self.run_list + Array(options[:run_list])).uniq
|
@@ -252,17 +252,4 @@ module Ridley
|
|
252
252
|
self
|
253
253
|
end
|
254
254
|
end
|
255
|
-
|
256
|
-
module DSL
|
257
|
-
# Coerces instance functions into class functions on Ridley::Node. This coercion
|
258
|
-
# sends an instance of the including class along to the class function.
|
259
|
-
#
|
260
|
-
# @see Ridley::ChainLink
|
261
|
-
#
|
262
|
-
# @return [Ridley::ChainLink]
|
263
|
-
# a context object to delegate instance functions to class functions on Ridley::Node
|
264
|
-
def node
|
265
|
-
ChainLink.new(self, Ridley::Node)
|
266
|
-
end
|
267
|
-
end
|
268
255
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Ridley
|
2
2
|
# @author Jamie Winsor <jamie@vialstudios.com>
|
3
|
-
class
|
3
|
+
class RoleResource < Ridley::Resource
|
4
4
|
set_chef_id "name"
|
5
5
|
set_chef_type "role"
|
6
6
|
set_chef_json_class "Chef::Role"
|
@@ -60,17 +60,4 @@ module Ridley
|
|
60
60
|
self.default_attributes = self.default_attributes.deep_merge(attr_hash)
|
61
61
|
end
|
62
62
|
end
|
63
|
-
|
64
|
-
module DSL
|
65
|
-
# Coerces instance functions into class functions on Ridley::Role. This coercion
|
66
|
-
# sends an instance of the including class along to the class function.
|
67
|
-
#
|
68
|
-
# @see Ridley::ChainLink
|
69
|
-
#
|
70
|
-
# @return [Ridley::ChainLink]
|
71
|
-
# a context object to delegate instance functions to class functions on Ridley::Role
|
72
|
-
def role
|
73
|
-
ChainLink.new(self, Ridley::Role)
|
74
|
-
end
|
75
|
-
end
|
76
63
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Ridley
|
2
|
+
# @author Jamie Winsor <jamie@vialstudios.com>
|
3
|
+
class SandboxResource
|
4
|
+
class << self
|
5
|
+
# Create a new Sandbox on the client's Chef Server. A Sandbox requires an
|
6
|
+
# array of file checksums which lets the Chef Server know what the signature
|
7
|
+
# of the contents to be uploaded will look like.
|
8
|
+
#
|
9
|
+
# @param [Ridley::Client] client
|
10
|
+
# @param [Array] checksums
|
11
|
+
# a hash of file checksums
|
12
|
+
#
|
13
|
+
# @example using the Ridley client to create a sandbox
|
14
|
+
# client.sandbox.create([
|
15
|
+
# "385ea5490c86570c7de71070bce9384a",
|
16
|
+
# "f6f73175e979bd90af6184ec277f760c",
|
17
|
+
# "2e03dd7e5b2e6c8eab1cf41ac61396d5"
|
18
|
+
# ])
|
19
|
+
#
|
20
|
+
# @return [Array<Ridley::SandboxResource>]
|
21
|
+
def create(client, checksums = [])
|
22
|
+
sumhash = { checksums: Hash.new }.tap do |chks|
|
23
|
+
Array(checksums).each { |chk| chks[:checksums][chk] = nil }
|
24
|
+
end
|
25
|
+
|
26
|
+
new(client, client.connection.post("sandboxes", MultiJson.encode(sumhash)).body)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
include Chozo::VariaModel
|
31
|
+
|
32
|
+
attribute :sandbox_id,
|
33
|
+
type: String
|
34
|
+
|
35
|
+
attribute :uri,
|
36
|
+
type: String
|
37
|
+
|
38
|
+
attribute :checksums,
|
39
|
+
type: Hash
|
40
|
+
|
41
|
+
attribute :is_completed,
|
42
|
+
type: Boolean,
|
43
|
+
default: false
|
44
|
+
|
45
|
+
attr_reader :client
|
46
|
+
|
47
|
+
# @param [Ridley::Client] client
|
48
|
+
# @param [Hash] new_attrs
|
49
|
+
def initialize(client, new_attrs = {})
|
50
|
+
@client = client
|
51
|
+
mass_assign(new_attrs)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Return information about the given checksum
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# sandbox.checksum("e5a0f6b48d0712382295ff30bec1f9cc") => {
|
58
|
+
# needs_upload: true,
|
59
|
+
# url: "https://s3.amazonaws.com/opscode-platform-production-data/organization"
|
60
|
+
# }
|
61
|
+
#
|
62
|
+
# @param [#to_sym] chk_id
|
63
|
+
# checksum to retrieve information about
|
64
|
+
#
|
65
|
+
# @return [Hash]
|
66
|
+
# a hash containing the checksum information
|
67
|
+
def checksum(chk_id)
|
68
|
+
checksums[chk_id.to_sym]
|
69
|
+
end
|
70
|
+
|
71
|
+
# Concurrently upload all of this sandboxes files into the checksum containers of the sandbox
|
72
|
+
def upload(checksums)
|
73
|
+
SandboxUploader.upload(self, checksums)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Notify the Chef Server that uploading to this sandbox has completed
|
77
|
+
def commit
|
78
|
+
response = client.connection.put("sandboxes/#{sandbox_id}", MultiJson.encode(is_completed: true)).body
|
79
|
+
set_attribute(:is_completed, response[:is_completed])
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_s
|
83
|
+
"#{sandbox_id}: #{checksums}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -3,20 +3,20 @@ module Ridley
|
|
3
3
|
class << self
|
4
4
|
# Returns an array of possible search indexes to be search on
|
5
5
|
#
|
6
|
-
# @param [Ridley::
|
6
|
+
# @param [Ridley::Client] client
|
7
7
|
#
|
8
8
|
# @example
|
9
9
|
#
|
10
|
-
# Search.indexes(
|
10
|
+
# Search.indexes(client) => [ :client, :environment, :node, :role ]
|
11
11
|
#
|
12
12
|
# @return [Array<String, Symbol>]
|
13
|
-
def indexes(
|
14
|
-
connection.get("search").body.collect { |name, _| name }
|
13
|
+
def indexes(client)
|
14
|
+
client.connection.get("search").body.collect { |name, _| name }
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
# @return [Ridley::
|
19
|
-
attr_reader :
|
18
|
+
# @return [Ridley::Client]
|
19
|
+
attr_reader :client
|
20
20
|
attr_reader :index
|
21
21
|
attr_reader :query
|
22
22
|
|
@@ -24,7 +24,7 @@ module Ridley
|
|
24
24
|
attr_accessor :rows
|
25
25
|
attr_accessor :start
|
26
26
|
|
27
|
-
# @param [Ridley::
|
27
|
+
# @param [Ridley::Client] client
|
28
28
|
# @param [#to_sym] index
|
29
29
|
# @param [#to_s] query
|
30
30
|
#
|
@@ -34,20 +34,19 @@ module Ridley
|
|
34
34
|
# how many rows to return
|
35
35
|
# @option options [Integer] :start
|
36
36
|
# the result number to start from
|
37
|
-
def initialize(
|
38
|
-
@
|
39
|
-
@index
|
40
|
-
@query
|
41
|
-
|
42
|
-
@
|
43
|
-
@
|
44
|
-
@start = options[:start]
|
37
|
+
def initialize(client, index, query, options = {})
|
38
|
+
@client = client
|
39
|
+
@index = index.to_sym
|
40
|
+
@query = query
|
41
|
+
@sort = options[:sort]
|
42
|
+
@rows = options[:rows]
|
43
|
+
@start = options[:start]
|
45
44
|
end
|
46
45
|
|
47
|
-
# Executes the built up query on the search's
|
46
|
+
# Executes the built up query on the search's client
|
48
47
|
#
|
49
48
|
# @example
|
50
|
-
# Search.new(
|
49
|
+
# Search.new(client, :role)
|
51
50
|
# search.run =>
|
52
51
|
# {
|
53
52
|
# total: 1,
|
@@ -68,17 +67,17 @@ module Ridley
|
|
68
67
|
#
|
69
68
|
# @return [Hash]
|
70
69
|
def run
|
71
|
-
response = connection.get(query_uri, query_options).body
|
70
|
+
response = client.connection.get(query_uri, query_options).body
|
72
71
|
|
73
72
|
case index
|
74
73
|
when :node
|
75
|
-
response[:rows].collect { |row|
|
74
|
+
response[:rows].collect { |row| Ridley::NodeResource.new(client, row) }
|
76
75
|
when :role
|
77
|
-
response[:rows].collect { |row|
|
76
|
+
response[:rows].collect { |row| Ridley::RoleResource.new(client, row) }
|
78
77
|
when :client
|
79
|
-
response[:rows].collect { |row|
|
78
|
+
response[:rows].collect { |row| Ridley::ClientResource.new(client, row) }
|
80
79
|
when :environment
|
81
|
-
response[:rows].collect { |row|
|
80
|
+
response[:rows].collect { |row| Ridley::EnvironmentResource.new(client, row) }
|
82
81
|
else
|
83
82
|
response[:rows]
|
84
83
|
end
|
@@ -92,41 +91,11 @@ module Ridley
|
|
92
91
|
|
93
92
|
def query_options
|
94
93
|
{}.tap do |options|
|
95
|
-
options[:q]
|
96
|
-
options[:sort]
|
97
|
-
options[:rows]
|
94
|
+
options[:q] = self.query unless self.query.nil?
|
95
|
+
options[:sort] = self.sort unless self.sort.nil?
|
96
|
+
options[:rows] = self.rows unless self.rows.nil?
|
98
97
|
options[:start] = self.start unless self.start.nil?
|
99
98
|
end
|
100
99
|
end
|
101
100
|
end
|
102
|
-
|
103
|
-
module DSL
|
104
|
-
# Creates an runs a new Ridley::Search
|
105
|
-
#
|
106
|
-
# @see Ridley::Search#run
|
107
|
-
#
|
108
|
-
# @param [String, Symbol] index
|
109
|
-
# @param [String, nil] query
|
110
|
-
#
|
111
|
-
# @option options [String] :sort
|
112
|
-
# @option options [Integer] :rows
|
113
|
-
# @option options [Integer] :start
|
114
|
-
#
|
115
|
-
# @return [Hash]
|
116
|
-
def search(index, query = nil, options = {})
|
117
|
-
Search.new(self, index, query, options).run
|
118
|
-
end
|
119
|
-
|
120
|
-
# Return the array of all possible search indexes for the including connection
|
121
|
-
#
|
122
|
-
# @example
|
123
|
-
# conn = Ridley.connection(...)
|
124
|
-
# conn.search_indexes =>
|
125
|
-
# [:client, :environment, :node, :role, :"ridley-two", :"ridley-one"]
|
126
|
-
#
|
127
|
-
# @return [Array<Symbol, String>]
|
128
|
-
def search_indexes
|
129
|
-
Search.indexes(self)
|
130
|
-
end
|
131
|
-
end
|
132
101
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Ridley
|
2
|
+
# @author Jamie Winsor <jamie@vialstudios.com>
|
3
|
+
# @api private
|
4
|
+
class SandboxUploader
|
5
|
+
class << self
|
6
|
+
# Concurrently upload all of the files in the given sandbox and then clean up
|
7
|
+
# after ourselves
|
8
|
+
#
|
9
|
+
# @param [Ridley::SandboxResource] sandbox
|
10
|
+
# @param [Hash] checksums
|
11
|
+
#
|
12
|
+
# @option options [Integer] :pool_size (12)
|
13
|
+
# the amount of concurrent uploads to perform
|
14
|
+
def upload(sandbox, checksums, options = {})
|
15
|
+
options = options.reverse_merge(
|
16
|
+
pool_size: 12
|
17
|
+
)
|
18
|
+
uploader = pool(size: options[:pool_size], args: [sandbox])
|
19
|
+
uploader.multi_upload(checksums)
|
20
|
+
ensure
|
21
|
+
uploader.terminate if uploader && uploader.alive?
|
22
|
+
end
|
23
|
+
|
24
|
+
# Return the checksum of the contents of the file at the given filepath
|
25
|
+
#
|
26
|
+
# @param [String] path
|
27
|
+
# file to checksum
|
28
|
+
#
|
29
|
+
# @return [String]
|
30
|
+
# the binary checksum of the contents of the file
|
31
|
+
def checksum(path)
|
32
|
+
File.open(path, 'rb') { |f| checksum_io(f, Digest::MD5.new) }
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return a base64 encoded checksum of the contents of hte given file. This is the expected
|
36
|
+
# format of sandbox checksums given to the Chef Server.
|
37
|
+
#
|
38
|
+
# @param [String] path
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
# a base64 encoded checksum
|
42
|
+
def checksum64(path)
|
43
|
+
Base64.encode64([checksum(path)].pack("H*")).strip
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param [String] io
|
47
|
+
# @param [Object] digest
|
48
|
+
#
|
49
|
+
# @return [String]
|
50
|
+
def checksum_io(io, digest)
|
51
|
+
while chunk = io.read(1024 * 8)
|
52
|
+
digest.update(chunk)
|
53
|
+
end
|
54
|
+
digest.hexdigest
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
extend Forwardable
|
59
|
+
include Celluloid
|
60
|
+
|
61
|
+
attr_reader :sandbox
|
62
|
+
|
63
|
+
def_delegator :sandbox, :client
|
64
|
+
def_delegator :sandbox, :checksum
|
65
|
+
|
66
|
+
def initialize(sandbox)
|
67
|
+
@sandbox = sandbox
|
68
|
+
end
|
69
|
+
|
70
|
+
# Concurrently upload multiple files into a sandbox
|
71
|
+
#
|
72
|
+
# @param [Hash] checksums
|
73
|
+
# a hash of file checksums and file paths
|
74
|
+
#
|
75
|
+
# @example uploading multiple checksums
|
76
|
+
#
|
77
|
+
# sandbox.multi_upload(
|
78
|
+
# "e5a0f6b48d0712382295ff30bec1f9cc" => "/Users/reset/code/rbenv-cookbook/recipes/default.rb",
|
79
|
+
# "de6532a7fbe717d52020dc9f3ae47dbe" => "/Users/reset/code/rbenv-cookbook/recipes/ohai_plugin.rb"
|
80
|
+
# )
|
81
|
+
def multi_upload(checksums)
|
82
|
+
checksums.collect do |chk_id, path|
|
83
|
+
future.upload(chk_id, path)
|
84
|
+
end.map(&:value)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Upload one file into the sandbox for the given checksum id
|
88
|
+
#
|
89
|
+
# @param [String] chk_id
|
90
|
+
# checksum of the file being uploaded
|
91
|
+
# @param [String] path
|
92
|
+
# path to the file to upload
|
93
|
+
#
|
94
|
+
# @return [Hash, nil]
|
95
|
+
def upload(chk_id, path)
|
96
|
+
checksum = self.checksum(chk_id)
|
97
|
+
|
98
|
+
unless checksum[:needs_upload]
|
99
|
+
return nil
|
100
|
+
end
|
101
|
+
|
102
|
+
headers = {
|
103
|
+
'Content-Type' => 'application/x-binary',
|
104
|
+
'content-md5' => self.class.checksum64(path)
|
105
|
+
}
|
106
|
+
contents = File.open(path, 'rb') { |f| f.read }
|
107
|
+
|
108
|
+
url = URI(checksum[:url])
|
109
|
+
upload_path = url.path
|
110
|
+
url.path = ""
|
111
|
+
|
112
|
+
Faraday.new(url) do |c|
|
113
|
+
c.request :chef_auth, client.client_name, client.client_key
|
114
|
+
c.adapter :net_http
|
115
|
+
end.put(upload_path, contents, headers)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|