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.
Files changed (85) hide show
  1. data/README.md +147 -216
  2. data/lib/ridley.rb +2 -0
  3. data/lib/ridley/bootstrap_bindings/unix_template_binding.rb +21 -25
  4. data/lib/ridley/bootstrap_bindings/windows_template_binding.rb +29 -34
  5. data/lib/ridley/bootstrapper.rb +2 -2
  6. data/lib/ridley/bootstrapper/context.rb +5 -5
  7. data/lib/ridley/chef.rb +0 -1
  8. data/lib/ridley/chef/cookbook.rb +0 -9
  9. data/lib/ridley/chef_object.rb +128 -0
  10. data/lib/ridley/chef_objects.rb +3 -0
  11. data/lib/ridley/chef_objects/client_object.rb +55 -0
  12. data/lib/ridley/chef_objects/cookbook_object.rb +190 -0
  13. data/lib/ridley/chef_objects/data_bag_item_obect.rb +104 -0
  14. data/lib/ridley/chef_objects/data_bag_object.rb +31 -0
  15. data/lib/ridley/chef_objects/environment_object.rb +59 -0
  16. data/lib/ridley/chef_objects/node_object.rb +161 -0
  17. data/lib/ridley/chef_objects/role_object.rb +62 -0
  18. data/lib/ridley/chef_objects/sandbox_object.rb +58 -0
  19. data/lib/ridley/client.rb +76 -45
  20. data/lib/ridley/connection.rb +1 -1
  21. data/lib/ridley/errors.rb +8 -1
  22. data/lib/ridley/host_connector.rb +26 -6
  23. data/lib/ridley/host_connector/ssh.rb +3 -3
  24. data/lib/ridley/host_connector/ssh/worker.rb +7 -9
  25. data/lib/ridley/host_connector/winrm/worker.rb +4 -5
  26. data/lib/ridley/mixin/bootstrap_binding.rb +1 -12
  27. data/lib/ridley/resource.rb +51 -171
  28. data/lib/ridley/resources/client_resource.rb +18 -68
  29. data/lib/ridley/resources/cookbook_resource.rb +181 -381
  30. data/lib/ridley/resources/data_bag_item_resource.rb +55 -161
  31. data/lib/ridley/resources/data_bag_resource.rb +20 -61
  32. data/lib/ridley/resources/environment_resource.rb +9 -64
  33. data/lib/ridley/resources/node_resource.rb +135 -311
  34. data/lib/ridley/resources/role_resource.rb +1 -57
  35. data/lib/ridley/resources/sandbox_resource.rb +80 -65
  36. data/lib/ridley/resources/search_resource.rb +99 -0
  37. data/lib/ridley/sandbox_uploader.rb +12 -52
  38. data/lib/ridley/version.rb +1 -1
  39. data/spec/acceptance/bootstrapping_spec.rb +1 -1
  40. data/spec/acceptance/client_resource_spec.rb +15 -37
  41. data/spec/acceptance/data_bag_item_resource_spec.rb +8 -14
  42. data/spec/acceptance/data_bag_resource_spec.rb +1 -1
  43. data/spec/acceptance/environment_resource_spec.rb +13 -22
  44. data/spec/acceptance/node_resource_spec.rb +10 -29
  45. data/spec/acceptance/role_resource_spec.rb +14 -13
  46. data/spec/acceptance/sandbox_resource_spec.rb +2 -2
  47. data/spec/support/shared_examples/ridley_resource.rb +2 -23
  48. data/spec/unit/ridley/bootstrap_bindings/unix_template_binding_spec.rb +3 -4
  49. data/spec/unit/ridley/bootstrap_bindings/windows_template_binding_spec.rb +3 -5
  50. data/spec/unit/ridley/bootstrapper/context_spec.rb +2 -3
  51. data/spec/unit/ridley/bootstrapper_spec.rb +1 -1
  52. data/spec/unit/ridley/chef_object_spec.rb +240 -0
  53. data/spec/unit/ridley/chef_objects/client_object_spec.rb +11 -0
  54. data/spec/unit/ridley/chef_objects/cookbook_object_spec.rb +93 -0
  55. data/spec/unit/ridley/chef_objects/data_bag_item_object_spec.rb +74 -0
  56. data/spec/unit/ridley/chef_objects/data_bag_object_spec.rb +9 -0
  57. data/spec/unit/ridley/chef_objects/environment_object_spec.rb +57 -0
  58. data/spec/unit/ridley/chef_objects/node_object_spec.rb +252 -0
  59. data/spec/unit/ridley/chef_objects/role_object_spec.rb +57 -0
  60. data/spec/unit/ridley/chef_objects/sandbox_object_spec.rb +66 -0
  61. data/spec/unit/ridley/client_spec.rb +51 -51
  62. data/spec/unit/ridley/host_connector/ssh/worker_spec.rb +4 -4
  63. data/spec/unit/ridley/host_connector/ssh_spec.rb +26 -24
  64. data/spec/unit/ridley/host_connector/winrm/worker_spec.rb +3 -4
  65. data/spec/unit/ridley/host_connector/winrm_spec.rb +4 -4
  66. data/spec/unit/ridley/host_connector_spec.rb +40 -3
  67. data/spec/unit/ridley/mixin/bootstrap_binding_spec.rb +1 -1
  68. data/spec/unit/ridley/resource_spec.rb +81 -109
  69. data/spec/unit/ridley/resources/client_resource_spec.rb +18 -33
  70. data/spec/unit/ridley/resources/cookbook_resource_spec.rb +56 -230
  71. data/spec/unit/ridley/resources/data_bag_item_resource_spec.rb +2 -57
  72. data/spec/unit/ridley/resources/data_bag_resource_spec.rb +12 -7
  73. data/spec/unit/ridley/resources/environment_resource_spec.rb +10 -118
  74. data/spec/unit/ridley/resources/node_resource_spec.rb +83 -394
  75. data/spec/unit/ridley/resources/role_resource_spec.rb +2 -56
  76. data/spec/unit/ridley/resources/sandbox_resource_spec.rb +139 -136
  77. data/spec/unit/ridley/resources/search_resource_spec.rb +234 -0
  78. data/spec/unit/ridley/sandbox_uploader_spec.rb +13 -58
  79. metadata +36 -17
  80. data/lib/ridley/chef/chefignore.rb +0 -76
  81. data/lib/ridley/resources/encrypted_data_bag_item_resource.rb +0 -55
  82. data/lib/ridley/resources/search.rb +0 -101
  83. data/spec/fixtures/chefignore +0 -8
  84. data/spec/unit/ridley/chef/chefignore_spec.rb +0 -40
  85. data/spec/unit/ridley/resources/search_spec.rb +0 -221
@@ -1,188 +1,82 @@
1
1
  module Ridley
2
2
  # @author Jamie Winsor <reset@riotgames.com>
3
3
  class DataBagItemResource < Ridley::Resource
4
- class << self
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
- new_attributes = client.connection.post("#{data_bag.class.resource_path}/#{data_bag.name}", resource.to_json).body
50
- resource.mass_assign(new_attributes)
51
- resource
52
- end
6
+ attr_reader :data_bag_secret
53
7
 
54
- # @param [Ridley::Client] client
55
- # @param [Ridley::DataBagResource] data_bag
56
- # @param [String, #chef_id] object
57
- #
58
- # @return [Ridley::DataBagItemResource]
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
- set_assignment_mode :carefree
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 [String]
115
- def chef_id
116
- get_attribute(:id)
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
- # Creates a resource on the target remote or updates one if the resource
120
- # already exists.
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 [Boolean]
126
- # true if successful and false for failure
127
- def save
128
- raise Errors::InvalidResource.new(self.errors) unless valid?
129
-
130
- mass_assign(self.class.create(client, data_bag, self)._attributes_)
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
- # Decrypts this data bag item.
35
+ # @param [Ridley::DataBagObject] data_bag
36
+ # @param [#to_hash] object
138
37
  #
139
- # @return [Hash] decrypted attributes
140
- def decrypt
141
- decrypted_hash = Hash[_attributes_.map { |key, value| [key, key == "id" ? value : decrypt_value(value)] }]
142
- mass_assign(decrypted_hash)
143
- end
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
- YAML.load(decrypted_value)
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
- # Reload the attributes of the instantiated resource
50
+ # @param [Ridley::DataBagObject] data_bag
51
+ # @param [String, #chef_id] object
157
52
  #
158
- # @return [Object]
159
- def reload
160
- mass_assign(self.class.find(client, data_bag, self)._attributes_)
161
- self
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
- # Updates the instantiated resource on the target remote with any changes made
165
- # to self
59
+ # @param [Ridley::DataBagObject] data_bag
166
60
  #
167
- # @raise [Errors::InvalidResource]
168
- # if the resource does not pass validations
169
- #
170
- # @return [Boolean]
171
- def update
172
- raise Errors::InvalidResource.new(self.errors) unless valid?
173
-
174
- mass_assign(self.class.update(client, data_bag, self)._attributes_)
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 [#to_hash] hash
71
+ # @param [Ridley::DataBagObject] data_bag
72
+ # @param [#to_hash] object
179
73
  #
180
- # @return [Object]
181
- def from_hash(hash)
182
- hash = Hashie::Mash.new(hash.to_hash)
183
-
184
- mass_assign(hash.has_key?(:raw_data) ? hash[:raw_data] : hash)
185
- self
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
- attribute :name,
64
- required: true
11
+ finalizer do
12
+ item_resource.terminate if item_resource && item_resource.alive?
13
+ end
65
14
 
66
- def item
67
- DBIChainLink.new(self, client)
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
- def encrypted_item
71
- DBIChainLink.new(self, client, encrypted: true)
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
- attribute :name,
23
- required: true
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 [HashWithIndifferentAccess]
68
- def set_override_attribute(key, value)
69
- attr_hash = HashWithIndifferentAccess.from_dotted_path(key, value)
70
- self.override_attributes = self.override_attributes.deep_merge(attr_hash)
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
- attribute :name,
159
- required: true
160
-
161
- attribute :chef_environment,
162
- default: "_default"
163
-
164
- attribute :automatic,
165
- default: Hashie::Mash.new
166
-
167
- attribute :normal,
168
- default: Hashie::Mash.new
169
-
170
- attribute :default,
171
- default: Hashie::Mash.new
172
-
173
- attribute :override,
174
- default: Hashie::Mash.new
175
-
176
- attribute :run_list,
177
- default: Array.new
178
-
179
- alias_method :normal_attributes, :normal
180
- alias_method :automatic_attributes, :automatic
181
- alias_method :default_attributes, :default
182
- alias_method :override_attributes, :override
183
-
184
- alias_method :normal_attributes=, :normal=
185
- alias_method :automatic_attributes=, :automatic=
186
- alias_method :default_attributes=, :default=
187
- alias_method :override_attributes=, :override=
188
-
189
- # Set a node level normal attribute given the dotted path representation of the Chef
190
- # attribute and value.
191
- #
192
- # @note It is not possible to set any other attribute level on a node and have it persist after
193
- # a Chef Run. This is because all other attribute levels are truncated at the start of a Chef Run.
194
- #
195
- # @example setting and saving a node level normal attribute
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
- # Returns the public hostname of the instantiated node. This hostname should be used for
211
- # public communications to the node.
212
- #
213
- # @example
214
- # node.public_hostname => "reset.riotgames.com"
215
- #
216
- # @return [String]
217
- def public_hostname
218
- self.cloud? ? self.automatic[:cloud][:public_hostname] : self.automatic[:fqdn]
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
- # Returns the public IPv4 address of the instantiated node. This ip address should be
222
- # used for public communications to the node.
100
+ # Executes a Chef run using the best worker available for the given
101
+ # host.
223
102
  #
224
- # @example
225
- # node.public_ipv4 => "10.33.33.1"
103
+ # @param [String] host
226
104
  #
227
- # @return [String]
228
- def public_ipv4
229
- self.cloud? ? self.automatic[:cloud][:public_ipv4] : self.automatic[:ipaddress]
230
- end
231
- alias_method :public_ipaddress, :public_ipv4
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
- # Returns true if the node is identified as a cloud node using the ec2 provider.
113
+ # Puts a secret on the host using the best worker available for
114
+ # the given host.
262
115
  #
263
- # @return [Boolean]
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 [Boolean]
271
- def rackspace?
272
- self.cloud_provider == "rackspace"
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
- # Run Chef-Client on the instantiated node.
126
+ # Executes an arbitrary ruby script using the best worker available
127
+ # for the given host.
276
128
  #
277
- # @param [Hash] options
278
- # a hash of options to pass to the best {Ridley::HostConnector}
129
+ # @param [String] host
130
+ # @param [Array<String>] command_lines
279
131
  #
280
132
  # @return [HostConnector::Response]
281
- def chef_client(options = {})
282
- connector_options = Hash.new
283
- connector_options[:ssh] = client.ssh
284
- connector_options[:winrm] = client.winrm
285
- connector_options.merge(options)
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
- # Put the client's encrypted data bag secret onto the instantiated node. If no
298
- # encrypted data bag key path is set on the resource's client then nil will be
299
- # returned
140
+ # Executes the given command on a node using the best worker
141
+ # available for the given host.
300
142
  #
301
- # @param [Hash] options
302
- # a hash of options to pass to the best {Ridley::HostConnector}
143
+ # @param [String] host
144
+ # @param [String] command
303
145
  #
304
- # @return [HostConnector::Response, nil]
305
- def put_secret(options = {})
306
- if client.encrypted_data_bag_secret_path.nil? ||
307
- !File.exists?(client.encrypted_data_bag_secret_path)
308
-
309
- return nil
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 instaniated nodes data with the given data and updates
327
- # the remote with the merged results
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
- unless options[:run_list].nil?
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