ridley 0.10.2 → 0.11.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 +147 -216
- data/lib/ridley.rb +2 -0
- data/lib/ridley/bootstrap_bindings/unix_template_binding.rb +21 -25
- data/lib/ridley/bootstrap_bindings/windows_template_binding.rb +29 -34
- data/lib/ridley/bootstrapper.rb +2 -2
- data/lib/ridley/bootstrapper/context.rb +5 -5
- data/lib/ridley/chef.rb +0 -1
- data/lib/ridley/chef/cookbook.rb +0 -9
- data/lib/ridley/chef_object.rb +128 -0
- data/lib/ridley/chef_objects.rb +3 -0
- data/lib/ridley/chef_objects/client_object.rb +55 -0
- data/lib/ridley/chef_objects/cookbook_object.rb +190 -0
- data/lib/ridley/chef_objects/data_bag_item_obect.rb +104 -0
- data/lib/ridley/chef_objects/data_bag_object.rb +31 -0
- data/lib/ridley/chef_objects/environment_object.rb +59 -0
- data/lib/ridley/chef_objects/node_object.rb +161 -0
- data/lib/ridley/chef_objects/role_object.rb +62 -0
- data/lib/ridley/chef_objects/sandbox_object.rb +58 -0
- data/lib/ridley/client.rb +76 -45
- data/lib/ridley/connection.rb +1 -1
- data/lib/ridley/errors.rb +8 -1
- data/lib/ridley/host_connector.rb +26 -6
- data/lib/ridley/host_connector/ssh.rb +3 -3
- data/lib/ridley/host_connector/ssh/worker.rb +7 -9
- data/lib/ridley/host_connector/winrm/worker.rb +4 -5
- data/lib/ridley/mixin/bootstrap_binding.rb +1 -12
- data/lib/ridley/resource.rb +51 -171
- data/lib/ridley/resources/client_resource.rb +18 -68
- data/lib/ridley/resources/cookbook_resource.rb +181 -381
- data/lib/ridley/resources/data_bag_item_resource.rb +55 -161
- data/lib/ridley/resources/data_bag_resource.rb +20 -61
- data/lib/ridley/resources/environment_resource.rb +9 -64
- data/lib/ridley/resources/node_resource.rb +135 -311
- data/lib/ridley/resources/role_resource.rb +1 -57
- data/lib/ridley/resources/sandbox_resource.rb +80 -65
- data/lib/ridley/resources/search_resource.rb +99 -0
- data/lib/ridley/sandbox_uploader.rb +12 -52
- data/lib/ridley/version.rb +1 -1
- data/spec/acceptance/bootstrapping_spec.rb +1 -1
- data/spec/acceptance/client_resource_spec.rb +15 -37
- data/spec/acceptance/data_bag_item_resource_spec.rb +8 -14
- data/spec/acceptance/data_bag_resource_spec.rb +1 -1
- data/spec/acceptance/environment_resource_spec.rb +13 -22
- data/spec/acceptance/node_resource_spec.rb +10 -29
- data/spec/acceptance/role_resource_spec.rb +14 -13
- data/spec/acceptance/sandbox_resource_spec.rb +2 -2
- data/spec/support/shared_examples/ridley_resource.rb +2 -23
- data/spec/unit/ridley/bootstrap_bindings/unix_template_binding_spec.rb +3 -4
- data/spec/unit/ridley/bootstrap_bindings/windows_template_binding_spec.rb +3 -5
- data/spec/unit/ridley/bootstrapper/context_spec.rb +2 -3
- data/spec/unit/ridley/bootstrapper_spec.rb +1 -1
- data/spec/unit/ridley/chef_object_spec.rb +240 -0
- data/spec/unit/ridley/chef_objects/client_object_spec.rb +11 -0
- data/spec/unit/ridley/chef_objects/cookbook_object_spec.rb +93 -0
- data/spec/unit/ridley/chef_objects/data_bag_item_object_spec.rb +74 -0
- data/spec/unit/ridley/chef_objects/data_bag_object_spec.rb +9 -0
- data/spec/unit/ridley/chef_objects/environment_object_spec.rb +57 -0
- data/spec/unit/ridley/chef_objects/node_object_spec.rb +252 -0
- data/spec/unit/ridley/chef_objects/role_object_spec.rb +57 -0
- data/spec/unit/ridley/chef_objects/sandbox_object_spec.rb +66 -0
- data/spec/unit/ridley/client_spec.rb +51 -51
- data/spec/unit/ridley/host_connector/ssh/worker_spec.rb +4 -4
- data/spec/unit/ridley/host_connector/ssh_spec.rb +26 -24
- data/spec/unit/ridley/host_connector/winrm/worker_spec.rb +3 -4
- data/spec/unit/ridley/host_connector/winrm_spec.rb +4 -4
- data/spec/unit/ridley/host_connector_spec.rb +40 -3
- data/spec/unit/ridley/mixin/bootstrap_binding_spec.rb +1 -1
- data/spec/unit/ridley/resource_spec.rb +81 -109
- data/spec/unit/ridley/resources/client_resource_spec.rb +18 -33
- data/spec/unit/ridley/resources/cookbook_resource_spec.rb +56 -230
- data/spec/unit/ridley/resources/data_bag_item_resource_spec.rb +2 -57
- data/spec/unit/ridley/resources/data_bag_resource_spec.rb +12 -7
- data/spec/unit/ridley/resources/environment_resource_spec.rb +10 -118
- data/spec/unit/ridley/resources/node_resource_spec.rb +83 -394
- data/spec/unit/ridley/resources/role_resource_spec.rb +2 -56
- data/spec/unit/ridley/resources/sandbox_resource_spec.rb +139 -136
- data/spec/unit/ridley/resources/search_resource_spec.rb +234 -0
- data/spec/unit/ridley/sandbox_uploader_spec.rb +13 -58
- metadata +36 -17
- data/lib/ridley/chef/chefignore.rb +0 -76
- data/lib/ridley/resources/encrypted_data_bag_item_resource.rb +0 -55
- data/lib/ridley/resources/search.rb +0 -101
- data/spec/fixtures/chefignore +0 -8
- data/spec/unit/ridley/chef/chefignore_spec.rb +0 -40
- data/spec/unit/ridley/resources/search_spec.rb +0 -221
@@ -1,188 +1,82 @@
|
|
1
1
|
module Ridley
|
2
2
|
# @author Jamie Winsor <reset@riotgames.com>
|
3
3
|
class DataBagItemResource < Ridley::Resource
|
4
|
-
|
5
|
-
# @param [Ridley::Client] client
|
6
|
-
#
|
7
|
-
# @return [Array<Object>]
|
8
|
-
def all(client, data_bag)
|
9
|
-
client.connection.get("#{data_bag.class.resource_path}/#{data_bag.name}").body.collect do |id, location|
|
10
|
-
new(client, data_bag, id: id)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
# @param [Ridley::Client] client
|
15
|
-
# @param [Ridley::DataBagResource] data_bag
|
16
|
-
# @param [String, #chef_id] object
|
17
|
-
#
|
18
|
-
# @return [nil, Ridley::DataBagItemResource]
|
19
|
-
def find(client, data_bag, object)
|
20
|
-
find!(client, data_bag, object)
|
21
|
-
rescue Errors::HTTPNotFound
|
22
|
-
nil
|
23
|
-
end
|
24
|
-
|
25
|
-
# @param [Ridley::Client] client
|
26
|
-
# @param [Ridley::DataBagResource] data_bag
|
27
|
-
# @param [String, #chef_id] object
|
28
|
-
#
|
29
|
-
# @raise [Errors::HTTPNotFound]
|
30
|
-
# if a resource with the given chef_id is not found
|
31
|
-
#
|
32
|
-
# @return [Ridley::DataBagItemResource]
|
33
|
-
def find!(client, data_bag, object)
|
34
|
-
chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
|
35
|
-
new(client, data_bag).from_hash(client.connection.get("#{data_bag.class.resource_path}/#{data_bag.name}/#{chef_id}").body)
|
36
|
-
end
|
37
|
-
|
38
|
-
# @param [Ridley::Client] client
|
39
|
-
# @param [Ridley::DataBagResource] data_bag
|
40
|
-
# @param [#to_hash] object
|
41
|
-
#
|
42
|
-
# @return [Ridley::DataBagItemResource]
|
43
|
-
def create(client, data_bag, object)
|
44
|
-
resource = new(client, data_bag, object.to_hash)
|
45
|
-
unless resource.valid?
|
46
|
-
raise Errors::InvalidResource.new(resource.errors)
|
47
|
-
end
|
4
|
+
represented_by Ridley::DataBagItemObject
|
48
5
|
|
49
|
-
|
50
|
-
resource.mass_assign(new_attributes)
|
51
|
-
resource
|
52
|
-
end
|
6
|
+
attr_reader :data_bag_secret
|
53
7
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
def delete(client, data_bag, object)
|
60
|
-
chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
|
61
|
-
new(client, data_bag).from_hash(client.connection.delete("#{data_bag.class.resource_path}/#{data_bag.name}/#{chef_id}").body)
|
62
|
-
end
|
63
|
-
|
64
|
-
# @param [Ridley::Client] client
|
65
|
-
# @param [Ridley::DataBagResource] data_bag
|
66
|
-
#
|
67
|
-
# @return [Array<Ridley::DataBagItemResource>]
|
68
|
-
def delete_all(client, data_bag)
|
69
|
-
mutex = Mutex.new
|
70
|
-
deleted = []
|
71
|
-
|
72
|
-
all(client, data_bag).collect do |resource|
|
73
|
-
Celluloid::Future.new {
|
74
|
-
delete(client, data_bag, resource)
|
75
|
-
}
|
76
|
-
end.map(&:value)
|
77
|
-
end
|
78
|
-
|
79
|
-
# @param [Ridley::Client] client
|
80
|
-
# @param [Ridley::DataBagResource] data_bag
|
81
|
-
# @param [#to_hash] object
|
82
|
-
#
|
83
|
-
# @return [Ridley::DataBagItemResource]
|
84
|
-
def update(client, data_bag, object)
|
85
|
-
resource = new(client, data_bag, object.to_hash)
|
86
|
-
new(client, data_bag).from_hash(
|
87
|
-
client.connection.put("#{data_bag.class.resource_path}/#{data_bag.name}/#{resource.chef_id}", resource.to_json).body
|
88
|
-
)
|
89
|
-
end
|
8
|
+
# @param [Celluloid::Registry] connection_registry
|
9
|
+
# @param [String] data_bag_secret
|
10
|
+
def initialize(connection_registry, data_bag_secret)
|
11
|
+
super(connection_registry)
|
12
|
+
@data_bag_secret = data_bag_secret
|
90
13
|
end
|
91
14
|
|
92
|
-
|
93
|
-
|
94
|
-
# @return [Ridley::DataBagResource]
|
95
|
-
attr_reader :data_bag
|
96
|
-
|
97
|
-
attribute :id,
|
98
|
-
type: String,
|
99
|
-
required: true
|
100
|
-
|
101
|
-
alias_method :attributes=, :mass_assign
|
102
|
-
alias_method :attributes, :_attributes_
|
103
|
-
|
104
|
-
# @param [Ridley::Client] client
|
105
|
-
# @param [Ridley::DataBagResource] data_bag
|
106
|
-
# @param [#to_hash] new_attrs
|
107
|
-
def initialize(client, data_bag, new_attrs = {})
|
108
|
-
super(client, new_attrs)
|
109
|
-
@data_bag = data_bag
|
110
|
-
end
|
111
|
-
|
112
|
-
# Alias for accessing the value of the 'id' attribute
|
15
|
+
# @param [Ridley::DataBagObject] data_bag
|
113
16
|
#
|
114
|
-
# @return [
|
115
|
-
def
|
116
|
-
|
17
|
+
# @return [Array<Object>]
|
18
|
+
def all(data_bag)
|
19
|
+
connection.get("#{DataBagResource.resource_path}/#{data_bag.name}").body.collect do |id, location|
|
20
|
+
new(data_bag, id: id)
|
21
|
+
end
|
117
22
|
end
|
118
23
|
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
# @raise [Errors::InvalidResource]
|
123
|
-
# if the resource does not pass validations
|
24
|
+
# @param [Ridley::DataBagObject] data_bag
|
25
|
+
# @param [String, #chef_id] object
|
124
26
|
#
|
125
|
-
# @return [
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
true
|
132
|
-
rescue Errors::HTTPConflict
|
133
|
-
self.update
|
134
|
-
true
|
27
|
+
# @return [Ridley::DataBagItemObject]
|
28
|
+
def find(data_bag, object)
|
29
|
+
chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
|
30
|
+
new(data_bag).from_hash(connection.get("#{DataBagResource.resource_path}/#{data_bag.name}/#{chef_id}").body)
|
31
|
+
rescue Errors::HTTPNotFound
|
32
|
+
nil
|
135
33
|
end
|
136
34
|
|
137
|
-
#
|
35
|
+
# @param [Ridley::DataBagObject] data_bag
|
36
|
+
# @param [#to_hash] object
|
138
37
|
#
|
139
|
-
# @return [
|
140
|
-
def
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
def decrypt_value(value)
|
146
|
-
decoded_value = Base64.decode64(value)
|
147
|
-
|
148
|
-
cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
|
149
|
-
cipher.decrypt
|
150
|
-
cipher.pkcs5_keyivgen(client.encrypted_data_bag_secret)
|
151
|
-
decrypted_value = cipher.update(decoded_value) + cipher.final
|
38
|
+
# @return [Ridley::DataBagItemObject]
|
39
|
+
def create(data_bag, object)
|
40
|
+
resource = new(data_bag, object.to_hash)
|
41
|
+
unless resource.valid?
|
42
|
+
abort Errors::InvalidResource.new(resource.errors)
|
43
|
+
end
|
152
44
|
|
153
|
-
|
45
|
+
new_attributes = connection.post("#{DataBagResource.resource_path}/#{data_bag.name}", resource.to_json).body
|
46
|
+
resource.mass_assign(new_attributes)
|
47
|
+
resource
|
154
48
|
end
|
155
49
|
|
156
|
-
#
|
50
|
+
# @param [Ridley::DataBagObject] data_bag
|
51
|
+
# @param [String, #chef_id] object
|
157
52
|
#
|
158
|
-
# @return [
|
159
|
-
def
|
160
|
-
|
161
|
-
|
53
|
+
# @return [Ridley::DataBagItemObject]
|
54
|
+
def delete(data_bag, object)
|
55
|
+
chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
|
56
|
+
new(data_bag).from_hash(connection.delete("#{DataBagResource.resource_path}/#{data_bag.name}/#{chef_id}").body)
|
162
57
|
end
|
163
58
|
|
164
|
-
#
|
165
|
-
# to self
|
59
|
+
# @param [Ridley::DataBagObject] data_bag
|
166
60
|
#
|
167
|
-
# @
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
true
|
61
|
+
# @return [Array<Ridley::DataBagItemObject>]
|
62
|
+
def delete_all(data_bag)
|
63
|
+
mutex = Mutex.new
|
64
|
+
deleted = []
|
65
|
+
|
66
|
+
all(data_bag).collect do |resource|
|
67
|
+
future(:delete, data_bag, resource)
|
68
|
+
end.map(&:value)
|
176
69
|
end
|
177
70
|
|
178
|
-
# @param [
|
71
|
+
# @param [Ridley::DataBagObject] data_bag
|
72
|
+
# @param [#to_hash] object
|
179
73
|
#
|
180
|
-
# @return [
|
181
|
-
def
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
74
|
+
# @return [Ridley::DataBagItemObject]
|
75
|
+
def update(data_bag, object)
|
76
|
+
resource = new(data_bag, object.to_hash)
|
77
|
+
new(data_bag).from_hash(
|
78
|
+
connection.put("#{DataBagResource.resource_path}/#{data_bag.name}/#{resource.chef_id}", resource.to_json).body
|
79
|
+
)
|
186
80
|
end
|
187
81
|
end
|
188
82
|
end
|
@@ -1,74 +1,33 @@
|
|
1
1
|
require 'ridley/resources/data_bag_item_resource'
|
2
|
-
require 'ridley/resources/encrypted_data_bag_item_resource'
|
3
2
|
|
4
3
|
module Ridley
|
5
|
-
# @author Jamie Winsor <reset@riotgames.com>
|
6
|
-
# @api private
|
7
|
-
class DBIChainLink
|
8
|
-
attr_reader :data_bag
|
9
|
-
attr_reader :client
|
10
|
-
attr_reader :klass
|
11
|
-
|
12
|
-
# @param [Ridley::DataBagResource] data_bag
|
13
|
-
# @param [Ridley::Client] client
|
14
|
-
#
|
15
|
-
# @option options [Boolean] :encrypted (false)
|
16
|
-
def initialize(data_bag, client, options = {})
|
17
|
-
options[:encrypted] ||= false
|
18
|
-
|
19
|
-
@data_bag = data_bag
|
20
|
-
@client = client
|
21
|
-
@klass = options[:encrypted] ? Ridley::EncryptedDataBagItemResource : Ridley::DataBagItemResource
|
22
|
-
end
|
23
|
-
|
24
|
-
def new(*args)
|
25
|
-
klass.send(:new, client, data_bag, *args)
|
26
|
-
end
|
27
|
-
|
28
|
-
def method_missing(fun, *args, &block)
|
29
|
-
klass.send(fun, client, data_bag, *args, &block)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
4
|
# @author Jamie Winsor <reset@riotgames.com>
|
34
5
|
class DataBagResource < Ridley::Resource
|
35
|
-
class << self
|
36
|
-
# @param [Ridley::Client] client
|
37
|
-
# @param [String, #chef_id] object
|
38
|
-
#
|
39
|
-
# @return [nil, Ridley::DataBagResource]
|
40
|
-
def find(client, object)
|
41
|
-
find!(client, object)
|
42
|
-
rescue Errors::HTTPNotFound
|
43
|
-
nil
|
44
|
-
end
|
45
|
-
|
46
|
-
# @param [Ridley::Client] client
|
47
|
-
# @param [String, #chef_id] object
|
48
|
-
#
|
49
|
-
# @raise [Errors::HTTPNotFound]
|
50
|
-
# if a resource with the given chef_id is not found
|
51
|
-
#
|
52
|
-
# @return [Ridley::DataBagResource]
|
53
|
-
def find!(client, object)
|
54
|
-
chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
|
55
|
-
client.connection.get("#{self.resource_path}/#{chef_id}")
|
56
|
-
new(client, name: chef_id)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
set_chef_id "name"
|
61
6
|
set_resource_path "data"
|
7
|
+
represented_by Ridley::DataBagObject
|
8
|
+
|
9
|
+
attr_reader :item_resource
|
62
10
|
|
63
|
-
|
64
|
-
|
11
|
+
finalizer do
|
12
|
+
item_resource.terminate if item_resource && item_resource.alive?
|
13
|
+
end
|
65
14
|
|
66
|
-
|
67
|
-
|
15
|
+
# @param [Celluloid::Registry] connection_registry
|
16
|
+
# @param [String] data_bag_secret
|
17
|
+
def initialize(connection_registry, data_bag_secret)
|
18
|
+
super(connection_registry)
|
19
|
+
@item_resource = DataBagItemResource.new_link(connection_registry, data_bag_secret)
|
68
20
|
end
|
69
21
|
|
70
|
-
|
71
|
-
|
22
|
+
# @param [String, #chef_id] object
|
23
|
+
#
|
24
|
+
# @return [nil, Ridley::DataBagResource]
|
25
|
+
def find(object)
|
26
|
+
chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
|
27
|
+
connection.get("#{self.class.resource_path}/#{chef_id}")
|
28
|
+
new(name: chef_id)
|
29
|
+
rescue Errors::HTTPNotFound
|
30
|
+
nil
|
72
31
|
end
|
73
32
|
end
|
74
33
|
end
|
@@ -1,73 +1,18 @@
|
|
1
1
|
module Ridley
|
2
2
|
# @author Jamie Winsor <reset@riotgames.com>
|
3
3
|
class EnvironmentResource < Ridley::Resource
|
4
|
-
class << self
|
5
|
-
# Delete all of the environments on the client. The '_default' environment
|
6
|
-
# will never be deleted.
|
7
|
-
#
|
8
|
-
# @param [Ridley::Client] client
|
9
|
-
#
|
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
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
set_chef_id "name"
|
18
|
-
set_chef_type "environment"
|
19
|
-
set_chef_json_class "Chef::Environment"
|
20
4
|
set_resource_path "environments"
|
5
|
+
represented_by Ridley::EnvironmentObject
|
21
6
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
attribute :description,
|
26
|
-
default: String.new
|
27
|
-
|
28
|
-
attribute :default_attributes,
|
29
|
-
default: Hashie::Mash.new
|
30
|
-
|
31
|
-
attribute :override_attributes,
|
32
|
-
default: Hashie::Mash.new
|
33
|
-
|
34
|
-
attribute :cookbook_versions,
|
35
|
-
default: Hashie::Mash.new
|
36
|
-
|
37
|
-
# Set an environment level default attribute given the dotted path representation of
|
38
|
-
# the Chef attribute and value
|
39
|
-
#
|
40
|
-
# @example setting and saving an environment level default attribute
|
41
|
-
#
|
42
|
-
# obj = environment.find("production")
|
43
|
-
# obj.set_default_attribute("my_app.billing.enabled", false)
|
44
|
-
# obj.save
|
45
|
-
#
|
46
|
-
# @param [String] key
|
47
|
-
# @param [Object] value
|
48
|
-
#
|
49
|
-
# @return [HashWithIndifferentAccess]
|
50
|
-
def set_default_attribute(key, value)
|
51
|
-
attr_hash = HashWithIndifferentAccess.from_dotted_path(key, value)
|
52
|
-
self.default_attributes = self.default_attributes.deep_merge(attr_hash)
|
53
|
-
end
|
54
|
-
|
55
|
-
# Set an environment level override attribute given the dotted path representation of
|
56
|
-
# the Chef attribute and value
|
57
|
-
#
|
58
|
-
# @example setting and saving an environment level override attribute
|
59
|
-
#
|
60
|
-
# obj = environment.find("production")
|
61
|
-
# obj.set_override_attribute("my_app.billing.enabled", false)
|
62
|
-
# obj.save
|
63
|
-
#
|
64
|
-
# @param [String] key
|
65
|
-
# @param [Object] value
|
7
|
+
# Delete all of the environments on the client. The '_default' environment
|
8
|
+
# will never be deleted.
|
66
9
|
#
|
67
|
-
# @return [
|
68
|
-
def
|
69
|
-
|
70
|
-
|
10
|
+
# @return [Array<Ridley::EnvironmentObject>]
|
11
|
+
def delete_all
|
12
|
+
envs = all.reject { |env| env.name.to_s == '_default' }
|
13
|
+
envs.collect do |resource|
|
14
|
+
future(:delete, resource)
|
15
|
+
end.map(&:value)
|
71
16
|
end
|
72
17
|
end
|
73
18
|
end
|
@@ -1,348 +1,172 @@
|
|
1
1
|
module Ridley
|
2
2
|
# @author Jamie Winsor <reset@riotgames.com>
|
3
3
|
class NodeResource < Ridley::Resource
|
4
|
-
class << self
|
5
|
-
# @overload bootstrap(client, nodes, options = {})
|
6
|
-
# @param [Ridley::Client] client
|
7
|
-
# @param [Array<String>, String] nodes
|
8
|
-
# @param [Hash] ssh
|
9
|
-
# * :user (String) a shell user that will login to each node and perform the bootstrap command on (required)
|
10
|
-
# * :password (String) the password for the shell user that will perform the bootstrap
|
11
|
-
# * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
|
12
|
-
# * :timeout (Float) [5.0] timeout value for SSH bootstrap
|
13
|
-
# @option options [Hash] :winrm
|
14
|
-
# * :user (String) a user that will login to each node and perform the bootstrap command on (required)
|
15
|
-
# * :password (String) the password for the user that will perform the bootstrap
|
16
|
-
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
|
17
|
-
# @option options [String] :validator_client
|
18
|
-
# @option options [String] :validator_path
|
19
|
-
# filepath to the validator used to bootstrap the node (required)
|
20
|
-
# @option options [String] :bootstrap_proxy
|
21
|
-
# URL to a proxy server to bootstrap through (default: nil)
|
22
|
-
# @option options [String] :encrypted_data_bag_secret_path
|
23
|
-
# filepath on your host machine to your organizations encrypted data bag secret (default: nil)
|
24
|
-
# @option options [Hash] :hints
|
25
|
-
# a hash of Ohai hints to place on the bootstrapped node (default: Hash.new)
|
26
|
-
# @option options [Hash] :attributes
|
27
|
-
# a hash of attributes to use in the first Chef run (default: Hash.new)
|
28
|
-
# @option options [Array] :run_list
|
29
|
-
# an initial run list to bootstrap with (default: Array.new)
|
30
|
-
# @option options [String] :chef_version
|
31
|
-
# version of Chef to install on the node (default: nil)
|
32
|
-
# @option options [String] :environment
|
33
|
-
# environment to join the node to (default: '_default')
|
34
|
-
# @option options [Boolean] :sudo
|
35
|
-
# bootstrap with sudo (default: true)
|
36
|
-
# @option options [String] :template
|
37
|
-
# bootstrap template to use (default: omnibus)
|
38
|
-
#
|
39
|
-
# @return [SSH::ResponseSet]
|
40
|
-
def bootstrap(client, *args)
|
41
|
-
options = args.extract_options!
|
42
|
-
|
43
|
-
default_options = {
|
44
|
-
server_url: client.server_url,
|
45
|
-
validator_path: client.validator_path,
|
46
|
-
validator_client: client.validator_client,
|
47
|
-
encrypted_data_bag_secret_path: client.encrypted_data_bag_secret_path,
|
48
|
-
ssh: client.ssh,
|
49
|
-
winrm: client.winrm,
|
50
|
-
chef_version: client.chef_version
|
51
|
-
}
|
52
|
-
|
53
|
-
options = default_options.merge(options)
|
54
|
-
Bootstrapper.new(args, options).run
|
55
|
-
end
|
56
|
-
|
57
|
-
# Executes a Chef run using the best worker available for the given
|
58
|
-
# host.
|
59
|
-
#
|
60
|
-
# @param [Ridley::Client] client
|
61
|
-
# @param [String] host
|
62
|
-
#
|
63
|
-
# @return [HostConnector::Response]
|
64
|
-
def chef_run(client, host)
|
65
|
-
worker = configured_worker_for(client, host)
|
66
|
-
worker.chef_client
|
67
|
-
ensure
|
68
|
-
worker.terminate if worker && worker.alive?
|
69
|
-
end
|
70
|
-
|
71
|
-
# Puts a secret on the host using the best worker available for
|
72
|
-
# the given host.
|
73
|
-
#
|
74
|
-
# @param [Ridley::Client] client
|
75
|
-
# @param [String] host
|
76
|
-
# @param [String] encrypted_data_bag_secret_path
|
77
|
-
#
|
78
|
-
# @return [HostConnector::Response]
|
79
|
-
def put_secret(client, host, encrypted_data_bag_secret_path)
|
80
|
-
worker = configured_worker_for(client, host)
|
81
|
-
worker.put_secret(encrypted_data_bag_secret_path)
|
82
|
-
ensure
|
83
|
-
worker.terminate if worker && worker.alive?
|
84
|
-
end
|
85
|
-
|
86
|
-
# Executes an arbitrary ruby script using the best worker available
|
87
|
-
# for the given host.
|
88
|
-
#
|
89
|
-
# @param [Ridley::Client] client
|
90
|
-
# @param [String] host
|
91
|
-
# @param [Array<String>] command_lines
|
92
|
-
#
|
93
|
-
# @return [HostConnector::Response]
|
94
|
-
def ruby_script(client, host, command_lines)
|
95
|
-
worker = configured_worker_for(client, host)
|
96
|
-
worker.ruby_script(command_lines)
|
97
|
-
ensure
|
98
|
-
worker.terminate if worker && worker.alive?
|
99
|
-
end
|
100
|
-
|
101
|
-
# Executes the given command on a node using the best worker
|
102
|
-
# available for the given host.
|
103
|
-
#
|
104
|
-
# @param [Ridley::Client] client
|
105
|
-
# @param [String] host
|
106
|
-
# @param [String] command
|
107
|
-
#
|
108
|
-
# @return [Array<Symbol, HostConnector::Response>]
|
109
|
-
def execute_command(client, host, command)
|
110
|
-
worker = configured_worker_for(client, host)
|
111
|
-
worker.run(command)
|
112
|
-
ensure
|
113
|
-
worker.terminate if worker && worker.alive?
|
114
|
-
end
|
115
|
-
|
116
|
-
# Merges the given data with the the data of the target node on the remote
|
117
|
-
#
|
118
|
-
# @param [Ridley::Client] client
|
119
|
-
# @param [Ridley::NodeResource, String] target
|
120
|
-
# node or identifier of the node to merge
|
121
|
-
#
|
122
|
-
# @option options [Array] :run_list
|
123
|
-
# run list items to merge
|
124
|
-
# @option options [Hash] :attributes
|
125
|
-
# attributes of normal precedence to merge
|
126
|
-
#
|
127
|
-
# @raise [Errors::HTTPNotFound]
|
128
|
-
# if the target node is not found
|
129
|
-
#
|
130
|
-
# @return [Ridley::NodeResource]
|
131
|
-
def merge_data(client, target, options = {})
|
132
|
-
find!(client, target).merge_data(options)
|
133
|
-
end
|
134
|
-
|
135
|
-
private
|
136
|
-
# @param [Ridley::Client] client
|
137
|
-
# @param [String] host
|
138
|
-
#
|
139
|
-
# @return [SSH::Worker, WinRM::Worker]
|
140
|
-
def configured_worker_for(client, host)
|
141
|
-
connector_options = Hash.new
|
142
|
-
connector_options[:ssh] = client.ssh
|
143
|
-
connector_options[:winrm] = client.winrm
|
144
|
-
|
145
|
-
HostConnector.best_connector_for(host, connector_options) do |host_connector|
|
146
|
-
host_connector::Worker.new(host, connector_options)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
4
|
include Ridley::Logging
|
152
5
|
|
153
|
-
set_chef_id "name"
|
154
|
-
set_chef_type "node"
|
155
|
-
set_chef_json_class "Chef::Node"
|
156
6
|
set_resource_path "nodes"
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
#
|
197
|
-
# obj = node.find("jwinsor-1")
|
198
|
-
# obj.set_chef_attribute("my_app.billing.enabled", false)
|
199
|
-
# obj.save
|
200
|
-
#
|
201
|
-
# @param [String] key
|
202
|
-
# @param [Object] value
|
203
|
-
#
|
204
|
-
# @return [Hashie::Mash]
|
205
|
-
def set_chef_attribute(key, value)
|
206
|
-
attr_hash = Hashie::Mash.from_dotted_path(key, value)
|
207
|
-
self.normal = self.normal.deep_merge(attr_hash)
|
7
|
+
represented_by Ridley::NodeObject
|
8
|
+
|
9
|
+
attr_reader :server_url
|
10
|
+
attr_reader :validator_path
|
11
|
+
attr_reader :validator_client
|
12
|
+
attr_reader :encrypted_data_bag_secret
|
13
|
+
attr_reader :ssh
|
14
|
+
attr_reader :winrm
|
15
|
+
attr_reader :chef_version
|
16
|
+
|
17
|
+
# @param [Celluloid::Registry] connection_registry
|
18
|
+
#
|
19
|
+
# @option options [String] :server_url
|
20
|
+
# URL to the Chef API
|
21
|
+
# @option options [Hash] ssh
|
22
|
+
# * :user (String) a shell user that will login to each node and perform the bootstrap command on
|
23
|
+
# * :password (String) the password for the shell user that will perform the bootstrap
|
24
|
+
# * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
|
25
|
+
# * :timeout (Float) [5.0] timeout value for SSH bootstrap
|
26
|
+
# @option options [Hash] :winrm
|
27
|
+
# * :user (String) a user that will login to each node and perform the bootstrap command on
|
28
|
+
# * :password (String) the password for the user that will perform the bootstrap
|
29
|
+
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on
|
30
|
+
# @option options [String] :validator_client
|
31
|
+
# @option options [String] :validator_path
|
32
|
+
# filepath to the validator used to bootstrap the node
|
33
|
+
# @option options [String] :encrypted_data_bag_secret
|
34
|
+
# your organizations encrypted data bag secret
|
35
|
+
# @option options [String] :chef_version
|
36
|
+
# version of Chef to install on the node (default: nil)
|
37
|
+
def initialize(connection_registry, options = {})
|
38
|
+
super(connection_registry)
|
39
|
+
@server_url = options[:server_url]
|
40
|
+
@validator_path = options[:validator_path]
|
41
|
+
@validator_client = options[:validator_client]
|
42
|
+
@encrypted_data_bag_secret = options[:encrypted_data_bag_secret]
|
43
|
+
@ssh = options[:ssh]
|
44
|
+
@winrm = options[:winrm]
|
45
|
+
@chef_version = options[:chef_version]
|
208
46
|
end
|
209
47
|
|
210
|
-
#
|
211
|
-
#
|
212
|
-
#
|
213
|
-
#
|
214
|
-
#
|
215
|
-
#
|
216
|
-
#
|
217
|
-
|
218
|
-
|
48
|
+
# @overload bootstrap(nodes, options = {})
|
49
|
+
# @param [Array<String>, String] nodes
|
50
|
+
#
|
51
|
+
# @option options [Hash] ssh
|
52
|
+
# * :user (String) a shell user that will login to each node and perform the bootstrap command on (required)
|
53
|
+
# * :password (String) the password for the shell user that will perform the bootstrap
|
54
|
+
# * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
|
55
|
+
# * :timeout (Float) [5.0] timeout value for SSH bootstrap
|
56
|
+
# @option options [Hash] :winrm
|
57
|
+
# * :user (String) a user that will login to each node and perform the bootstrap command on (required)
|
58
|
+
# * :password (String) the password for the user that will perform the bootstrap
|
59
|
+
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
|
60
|
+
# @option options [String] :validator_client
|
61
|
+
# @option options [String] :validator_path
|
62
|
+
# filepath to the validator used to bootstrap the node (required)
|
63
|
+
# @option options [String] :bootstrap_proxy
|
64
|
+
# URL to a proxy server to bootstrap through (default: nil)
|
65
|
+
# @option options [String] :encrypted_data_bag_secret_path
|
66
|
+
# filepath on your host machine to your organizations encrypted data bag secret (default: nil)
|
67
|
+
# @option options [Hash] :hints
|
68
|
+
# a hash of Ohai hints to place on the bootstrapped node (default: Hash.new)
|
69
|
+
# @option options [Hash] :attributes
|
70
|
+
# a hash of attributes to use in the first Chef run (default: Hash.new)
|
71
|
+
# @option options [Array] :run_list
|
72
|
+
# an initial run list to bootstrap with (default: Array.new)
|
73
|
+
# @option options [String] :chef_version
|
74
|
+
# version of Chef to install on the node (default: nil)
|
75
|
+
# @option options [String] :environment
|
76
|
+
# environment to join the node to (default: '_default')
|
77
|
+
# @option options [Boolean] :sudo
|
78
|
+
# bootstrap with sudo (default: true)
|
79
|
+
# @option options [String] :template
|
80
|
+
# bootstrap template to use (default: omnibus)
|
81
|
+
#
|
82
|
+
# @return [SSH::ResponseSet]
|
83
|
+
def bootstrap(*args)
|
84
|
+
args = args.dup
|
85
|
+
opts = args.extract_options!
|
86
|
+
|
87
|
+
options = opts.reverse_merge(
|
88
|
+
server_url: server_url,
|
89
|
+
validator_path: validator_path,
|
90
|
+
validator_client: validator_client,
|
91
|
+
encrypted_data_bag_secret: encrypted_data_bag_secret,
|
92
|
+
ssh: ssh,
|
93
|
+
winrm: winrm,
|
94
|
+
chef_version: chef_version
|
95
|
+
)
|
96
|
+
|
97
|
+
Bootstrapper.new(args, options).run
|
219
98
|
end
|
220
99
|
|
221
|
-
#
|
222
|
-
#
|
100
|
+
# Executes a Chef run using the best worker available for the given
|
101
|
+
# host.
|
223
102
|
#
|
224
|
-
# @
|
225
|
-
# node.public_ipv4 => "10.33.33.1"
|
103
|
+
# @param [String] host
|
226
104
|
#
|
227
|
-
# @return [
|
228
|
-
def
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
# Returns the cloud provider of the instantiated node. If the node is not identified as
|
234
|
-
# a cloud node, then nil is returned.
|
235
|
-
#
|
236
|
-
# @example
|
237
|
-
# node_1.cloud_provider => "eucalyptus"
|
238
|
-
# node_2.cloud_provider => "ec2"
|
239
|
-
# node_3.cloud_provider => "rackspace"
|
240
|
-
# node_4.cloud_provider => nil
|
241
|
-
#
|
242
|
-
# @return [nil, String]
|
243
|
-
def cloud_provider
|
244
|
-
self.cloud? ? self.automatic[:cloud][:provider] : nil
|
245
|
-
end
|
246
|
-
|
247
|
-
# Returns true if the node is identified as a cloud node.
|
248
|
-
#
|
249
|
-
# @return [Boolean]
|
250
|
-
def cloud?
|
251
|
-
self.automatic.has_key?(:cloud)
|
252
|
-
end
|
253
|
-
|
254
|
-
# Returns true if the node is identified as a cloud node using the eucalyptus provider.
|
255
|
-
#
|
256
|
-
# @return [Boolean]
|
257
|
-
def eucalyptus?
|
258
|
-
self.cloud_provider == "eucalyptus"
|
105
|
+
# @return [HostConnector::Response]
|
106
|
+
def chef_run(host)
|
107
|
+
worker = HostConnector.new(host, ssh: ssh, winrm: winrm)
|
108
|
+
worker.chef_client
|
109
|
+
ensure
|
110
|
+
worker.terminate if worker && worker.alive?
|
259
111
|
end
|
260
112
|
|
261
|
-
#
|
113
|
+
# Puts a secret on the host using the best worker available for
|
114
|
+
# the given host.
|
262
115
|
#
|
263
|
-
# @
|
264
|
-
def ec2?
|
265
|
-
self.cloud_provider == "ec2"
|
266
|
-
end
|
267
|
-
|
268
|
-
# Returns true if the node is identified as a cloud node using the rackspace provider.
|
116
|
+
# @param [String] host
|
269
117
|
#
|
270
|
-
# @return [
|
271
|
-
def
|
272
|
-
|
118
|
+
# @return [HostConnector::Response]
|
119
|
+
def put_secret(host)
|
120
|
+
worker = HostConnector.new(host, ssh: ssh, winrm: winrm)
|
121
|
+
worker.put_secret(encrypted_data_bag_secret)
|
122
|
+
ensure
|
123
|
+
worker.terminate if worker && worker.alive?
|
273
124
|
end
|
274
125
|
|
275
|
-
#
|
126
|
+
# Executes an arbitrary ruby script using the best worker available
|
127
|
+
# for the given host.
|
276
128
|
#
|
277
|
-
# @param [
|
278
|
-
#
|
129
|
+
# @param [String] host
|
130
|
+
# @param [Array<String>] command_lines
|
279
131
|
#
|
280
132
|
# @return [HostConnector::Response]
|
281
|
-
def
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
log.debug "Running Chef Client on: #{self.public_hostname}"
|
288
|
-
|
289
|
-
HostConnector.best_connector_for(self.public_hostname, connector_options) do |host_connector|
|
290
|
-
host_connector.start(self, connector_options) do |connector|
|
291
|
-
_, response = connector.chef_client
|
292
|
-
response
|
293
|
-
end
|
294
|
-
end
|
133
|
+
def ruby_script(host, command_lines)
|
134
|
+
worker = HostConnector.new(host, ssh: ssh, winrm: winrm)
|
135
|
+
worker.ruby_script(command_lines)
|
136
|
+
ensure
|
137
|
+
worker.terminate if worker && worker.alive?
|
295
138
|
end
|
296
139
|
|
297
|
-
#
|
298
|
-
#
|
299
|
-
# returned
|
140
|
+
# Executes the given command on a node using the best worker
|
141
|
+
# available for the given host.
|
300
142
|
#
|
301
|
-
# @param [
|
302
|
-
#
|
143
|
+
# @param [String] host
|
144
|
+
# @param [String] command
|
303
145
|
#
|
304
|
-
# @return [HostConnector::Response
|
305
|
-
def
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
end
|
311
|
-
|
312
|
-
connector_options = Hash.new
|
313
|
-
connector_options[:ssh] = client.ssh
|
314
|
-
connector_options[:winrm] = client.winrm
|
315
|
-
|
316
|
-
log.debug "Writing Encrypted Data Bag Secret to: #{self.public_hostname}"
|
317
|
-
|
318
|
-
HostConnector.best_connector_for(self.public_hostname, connector_options) do |host_connector|
|
319
|
-
host_connector.start(self, connector_options) do |connector|
|
320
|
-
_, response = connector.put_secret(client.encrypted_data_bag_secret_path)
|
321
|
-
response
|
322
|
-
end
|
323
|
-
end
|
146
|
+
# @return [Array<Symbol, HostConnector::Response>]
|
147
|
+
def execute_command(host, command)
|
148
|
+
worker = HostConnector.new(host, ssh: ssh, winrm: winrm)
|
149
|
+
worker.run(command)
|
150
|
+
ensure
|
151
|
+
worker.terminate if worker && worker.alive?
|
324
152
|
end
|
325
153
|
|
326
|
-
# Merges the
|
327
|
-
#
|
154
|
+
# Merges the given data with the the data of the target node on the remote
|
155
|
+
#
|
156
|
+
# @param [Ridley::NodeResource, String] target
|
157
|
+
# node or identifier of the node to merge
|
328
158
|
#
|
329
159
|
# @option options [Array] :run_list
|
330
160
|
# run list items to merge
|
331
161
|
# @option options [Hash] :attributes
|
332
162
|
# attributes of normal precedence to merge
|
333
163
|
#
|
164
|
+
# @raise [Errors::HTTPNotFound]
|
165
|
+
# if the target node is not found
|
166
|
+
#
|
334
167
|
# @return [Ridley::NodeResource]
|
335
|
-
def merge_data(options = {})
|
336
|
-
|
337
|
-
self.run_list = (self.run_list + Array(options[:run_list])).uniq
|
338
|
-
end
|
339
|
-
|
340
|
-
unless options[:attributes].nil?
|
341
|
-
self.normal = self.normal.deep_merge(options[:attributes])
|
342
|
-
end
|
343
|
-
|
344
|
-
self.update
|
345
|
-
self
|
168
|
+
def merge_data(target, options = {})
|
169
|
+
find(target).merge_data(options)
|
346
170
|
end
|
347
171
|
end
|
348
172
|
end
|