ridley 0.10.2 → 0.11.0.rc1

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