chef-api 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/CHANGELOG.md +17 -0
- data/README.md +42 -0
- data/chef-api.gemspec +1 -1
- data/lib/chef-api/configurable.rb +3 -2
- data/lib/chef-api/connection.rb +77 -47
- data/lib/chef-api/defaults.rb +28 -8
- data/lib/chef-api/errors.rb +32 -3
- data/lib/chef-api/resource.rb +1 -0
- data/lib/chef-api/resources/base.rb +30 -21
- data/lib/chef-api/resources/client.rb +6 -8
- data/lib/chef-api/resources/collection_proxy.rb +19 -2
- data/lib/chef-api/resources/data_bag.rb +1 -1
- data/lib/chef-api/resources/organization.rb +22 -0
- data/lib/chef-api/resources/user.rb +72 -1
- data/lib/chef-api/schema.rb +59 -21
- data/lib/chef-api/version.rb +1 -1
- data/lib/chef-api.rb +26 -5
- data/spec/integration/resources/client_spec.rb +54 -0
- data/spec/integration/resources/user_spec.rb +8 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/chef_server.rb +1 -0
- data/spec/unit/errors_spec.rb +294 -0
- data/spec/unit/resources/client_spec.rb +0 -16
- data/spec/unit/resources/connection_spec.rb +51 -0
- data/templates/errors/abstract_method.erb +5 -0
- data/templates/errors/cannot_regenerate_key.erb +1 -0
- data/templates/errors/chef_api_error.erb +1 -0
- data/templates/errors/file_not_found.erb +1 -0
- data/templates/errors/http_bad_request.erb +3 -0
- data/templates/errors/http_forbidden_request.erb +3 -0
- data/templates/errors/http_gateway_timeout.erb +3 -0
- data/templates/errors/http_method_not_allowed.erb +3 -0
- data/templates/errors/http_not_acceptable.erb +3 -0
- data/templates/errors/http_not_found.erb +3 -0
- data/templates/errors/http_server_unavailable.erb +1 -0
- data/templates/errors/http_unauthorized_request.erb +3 -0
- data/templates/errors/insufficient_file_permissions.erb +1 -0
- data/templates/errors/invalid_resource.erb +1 -0
- data/templates/errors/invalid_validator.erb +1 -0
- data/templates/errors/missing_url_parameter.erb +1 -0
- data/templates/errors/not_a_directory.erb +1 -0
- data/templates/errors/resource_already_exists.erb +1 -0
- data/templates/errors/resource_not_found.erb +1 -0
- data/templates/errors/resource_not_mutable.erb +1 -0
- data/templates/errors/unknown_attribute.erb +1 -0
- metadata +43 -17
- data/lib/chef-api/logger.rb +0 -160
- data/lib/chef-api/proxy.rb +0 -72
- data/locales/en.yml +0 -89
@@ -20,7 +20,7 @@ module ChefAPI
|
|
20
20
|
# @todo doc
|
21
21
|
#
|
22
22
|
def from_url(url, prefix = {})
|
23
|
-
from_json(
|
23
|
+
from_json(connection.get(url), prefix)
|
24
24
|
end
|
25
25
|
|
26
26
|
#
|
@@ -78,13 +78,13 @@ module ChefAPI
|
|
78
78
|
# has_many :environments, class_name: 'Environment'
|
79
79
|
#
|
80
80
|
def has_many(method, options = {})
|
81
|
-
class_name = options[:class_name] || Util.camelize(method).sub(/s$/, '')
|
81
|
+
class_name = options[:class_name] || "Resource::#{Util.camelize(method).sub(/s$/, '')}"
|
82
82
|
rest_endpoint = options[:rest_endpoint] || method
|
83
83
|
|
84
84
|
class_eval <<-EOH, __FILE__, __LINE__ + 1
|
85
85
|
def #{method}
|
86
86
|
associations[:#{method}] ||=
|
87
|
-
CollectionProxy.new(self, #{class_name}, '#{rest_endpoint}')
|
87
|
+
Resource::CollectionProxy.new(self, #{class_name}, '#{rest_endpoint}')
|
88
88
|
end
|
89
89
|
EOH
|
90
90
|
end
|
@@ -138,7 +138,7 @@ module ChefAPI
|
|
138
138
|
#
|
139
139
|
def post(body, prefix = {})
|
140
140
|
path = expanded_collection_path(prefix)
|
141
|
-
|
141
|
+
connection.post(path, body)
|
142
142
|
end
|
143
143
|
|
144
144
|
#
|
@@ -159,7 +159,7 @@ module ChefAPI
|
|
159
159
|
#
|
160
160
|
def put(id, body, prefix = {})
|
161
161
|
path = resource_path(id, prefix)
|
162
|
-
|
162
|
+
connection.put(path, body)
|
163
163
|
end
|
164
164
|
|
165
165
|
#
|
@@ -173,7 +173,7 @@ module ChefAPI
|
|
173
173
|
#
|
174
174
|
def delete(id, prefix = {})
|
175
175
|
path = resource_path(id, prefix)
|
176
|
-
|
176
|
+
connection.delete(path)
|
177
177
|
true
|
178
178
|
rescue Error::HTTPNotFound
|
179
179
|
true
|
@@ -195,7 +195,7 @@ module ChefAPI
|
|
195
195
|
#
|
196
196
|
def list(prefix = {})
|
197
197
|
path = expanded_collection_path(prefix)
|
198
|
-
|
198
|
+
connection.get(path).keys.sort
|
199
199
|
end
|
200
200
|
|
201
201
|
#
|
@@ -249,7 +249,7 @@ module ChefAPI
|
|
249
249
|
return nil if id.nil?
|
250
250
|
|
251
251
|
path = resource_path(id, prefix)
|
252
|
-
response =
|
252
|
+
response = connection.get(path)
|
253
253
|
from_json(response, prefix)
|
254
254
|
rescue Error::HTTPNotFound
|
255
255
|
nil
|
@@ -363,7 +363,7 @@ module ChefAPI
|
|
363
363
|
#
|
364
364
|
def each(prefix = {}, &block)
|
365
365
|
collection(prefix).each do |resource, path|
|
366
|
-
response =
|
366
|
+
response = connection.get(path)
|
367
367
|
result = from_json(response, prefix)
|
368
368
|
|
369
369
|
block.call(result) if block
|
@@ -383,9 +383,8 @@ module ChefAPI
|
|
383
383
|
#
|
384
384
|
# Return an array of all resources in the collection.
|
385
385
|
#
|
386
|
-
# @
|
387
|
-
#
|
388
|
-
# {size} and {each} methods instead as they are much more perforant.
|
386
|
+
# @note Unless you need the _entire_ collection, please consider using the
|
387
|
+
# {size} and {each} methods instead as they are much more perforant.
|
389
388
|
#
|
390
389
|
# @return [Array<Resource::Base>]
|
391
390
|
#
|
@@ -470,7 +469,7 @@ module ChefAPI
|
|
470
469
|
# a list of resources in the collection
|
471
470
|
#
|
472
471
|
def collection(prefix = {})
|
473
|
-
|
472
|
+
connection.get(expanded_collection_path(prefix))
|
474
473
|
end
|
475
474
|
|
476
475
|
#
|
@@ -516,6 +515,15 @@ module ChefAPI
|
|
516
515
|
URI.escape(value)
|
517
516
|
end.sub(/^\//, '') # Remove leading slash
|
518
517
|
end
|
518
|
+
|
519
|
+
#
|
520
|
+
# The current connection object.
|
521
|
+
#
|
522
|
+
# @return [ChefAPI::Connection]
|
523
|
+
#
|
524
|
+
def connection
|
525
|
+
Thread.current['chefapi.connection'] || ChefAPI.connection
|
526
|
+
end
|
519
527
|
end
|
520
528
|
|
521
529
|
#
|
@@ -546,6 +554,9 @@ module ChefAPI
|
|
546
554
|
# the list of prefix options (for nested resources)
|
547
555
|
#
|
548
556
|
def initialize(attributes = {}, prefix = {})
|
557
|
+
@schema = self.class.schema.dup
|
558
|
+
@schema.load_flavor(self.class.connection.flavor)
|
559
|
+
|
549
560
|
@associations = {}
|
550
561
|
@_prefix = prefix
|
551
562
|
|
@@ -571,7 +582,7 @@ module ChefAPI
|
|
571
582
|
# the primary key for this resource
|
572
583
|
#
|
573
584
|
def primary_key
|
574
|
-
|
585
|
+
@schema.primary_key
|
575
586
|
end
|
576
587
|
|
577
588
|
#
|
@@ -596,7 +607,7 @@ module ChefAPI
|
|
596
607
|
# @return [Hash<Symbol, Object>]
|
597
608
|
#
|
598
609
|
def _attributes
|
599
|
-
@_attributes ||= {}.merge(
|
610
|
+
@_attributes ||= {}.merge(@schema.attributes)
|
600
611
|
end
|
601
612
|
|
602
613
|
#
|
@@ -636,8 +647,7 @@ module ChefAPI
|
|
636
647
|
# so they will be reloaded the next time they are requested. If the remote
|
637
648
|
# record does not exist, no attributes are modified.
|
638
649
|
#
|
639
|
-
# @
|
640
|
-
# This will remove any custom values you have set on the resource!
|
650
|
+
# @note This will remove any custom values you have set on the resource!
|
641
651
|
#
|
642
652
|
# @return [self]
|
643
653
|
# the instance of the reloaded record
|
@@ -748,7 +758,7 @@ module ChefAPI
|
|
748
758
|
# the list of validators for this resource
|
749
759
|
#
|
750
760
|
def validators
|
751
|
-
@validators ||=
|
761
|
+
@validators ||= @schema.validators
|
752
762
|
end
|
753
763
|
|
754
764
|
#
|
@@ -845,8 +855,7 @@ module ChefAPI
|
|
845
855
|
# bacon.description = "My new description"
|
846
856
|
# bacon.diff #=> { :description => { :local => "My new description", :remote => "Old description" } }
|
847
857
|
#
|
848
|
-
# @
|
849
|
-
# This is a VERY expensive operation - use it sparringly!
|
858
|
+
# @note This is a VERY expensive operation - use it sparringly!
|
850
859
|
#
|
851
860
|
# @return [Hash]
|
852
861
|
#
|
@@ -887,7 +896,7 @@ module ChefAPI
|
|
887
896
|
# @return [Boolean]
|
888
897
|
#
|
889
898
|
def ignore_attribute?(key)
|
890
|
-
|
899
|
+
@schema.ignored_attributes.has_key?(key.to_sym)
|
891
900
|
end
|
892
901
|
|
893
902
|
#
|
@@ -26,7 +26,7 @@ module ChefAPI
|
|
26
26
|
# @return [Resource::Client]
|
27
27
|
#
|
28
28
|
def from_file(path)
|
29
|
-
name,
|
29
|
+
name, key = Util.safe_read(path)
|
30
30
|
|
31
31
|
if client = fetch(name)
|
32
32
|
client.private_key = key
|
@@ -63,15 +63,13 @@ module ChefAPI
|
|
63
63
|
# key = client.regenerate_key
|
64
64
|
# key #=> "-----BEGIN PRIVATE KEY-----\nMIGfMA0GCS..."
|
65
65
|
#
|
66
|
-
# @
|
67
|
-
#
|
68
|
-
#
|
69
|
-
# to
|
70
|
-
# +nil+ after you have committed it to disk and perform a manual GC to
|
66
|
+
# @note For security reasons, you should perform this operation sparingly!
|
67
|
+
# The resulting private key is committed to this object, meaning it is
|
68
|
+
# saved to memory somewhere. You should set this resource's +private_key+
|
69
|
+
# to +nil+ after you have committed it to disk and perform a manual GC to
|
71
70
|
# be ultra-secure.
|
72
71
|
#
|
73
|
-
# @
|
74
|
-
# Regenerating the private key also regenerates the public key!
|
72
|
+
# @note Regenerating the private key also regenerates the public key!
|
75
73
|
#
|
76
74
|
# @return [self]
|
77
75
|
# the current resource with the new public and private key attributes
|
@@ -157,6 +157,11 @@ module ChefAPI
|
|
157
157
|
#
|
158
158
|
# ["item_1", "item_2"]
|
159
159
|
#
|
160
|
+
# Or if the Chef Server is feeling especially magical, it might return the
|
161
|
+
# actual objects, but prefixed with the JSON id:
|
162
|
+
#
|
163
|
+
# [{"organization" => {"_id" => "..."}}, {"organization" => {...}}]
|
164
|
+
#
|
160
165
|
# So, this method attempts to intelligent handle these use cases. That being
|
161
166
|
# said, I can almost guarantee that someone is going to do some crazy
|
162
167
|
# strange edge case with this library and hit a bug here, so it will likely
|
@@ -165,9 +170,21 @@ module ChefAPI
|
|
165
170
|
# @return [Hash]
|
166
171
|
#
|
167
172
|
def load_collection
|
168
|
-
case response =
|
173
|
+
case response = Resource::Base.connection.get(endpoint)
|
169
174
|
when Array
|
170
|
-
|
175
|
+
if response.first.is_a?(Hash)
|
176
|
+
key = klass.schema.primary_key.to_s
|
177
|
+
|
178
|
+
{}.tap do |hash|
|
179
|
+
response.each do |results|
|
180
|
+
results.each do |_, info|
|
181
|
+
hash[key] = klass.resource_path(info[key])
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
else
|
186
|
+
Hash[*response.map { |item| [item, klass.resource_path(item)] }.flatten]
|
187
|
+
end
|
171
188
|
when Hash
|
172
189
|
response
|
173
190
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ChefAPI
|
2
|
+
class Resource::Organization < Resource::Base
|
3
|
+
collection_path '/organizations'
|
4
|
+
|
5
|
+
schema do
|
6
|
+
attribute :name, type: String, primary: true, required: true
|
7
|
+
attribute :org_type, type: String
|
8
|
+
attribute :full_name, type: String
|
9
|
+
attribute :clientname, type: String
|
10
|
+
attribute :guid, type: String
|
11
|
+
|
12
|
+
ignore :_id
|
13
|
+
ignore :_rev
|
14
|
+
ignore :chargify_subscription_id
|
15
|
+
ignore :chargify_customer_id
|
16
|
+
ignore :billing_plan
|
17
|
+
ignore :requester_id
|
18
|
+
ignore :assigned_at
|
19
|
+
ignore 'couchrest-type'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -3,9 +3,80 @@ module ChefAPI
|
|
3
3
|
collection_path '/users'
|
4
4
|
|
5
5
|
schema do
|
6
|
-
|
6
|
+
flavor :enterprise do
|
7
|
+
attribute :username, type: String, primary: true, required: true
|
8
|
+
|
9
|
+
# "Vanity" attributes
|
10
|
+
attribute :first_name, type: String
|
11
|
+
attribute :middle_name, type: String
|
12
|
+
attribute :last_name, type: String
|
13
|
+
attribute :display_name, type: String
|
14
|
+
attribute :email, type: String
|
15
|
+
attribute :city, type: String
|
16
|
+
attribute :country, type: String
|
17
|
+
attribute :twitter_account, type: String
|
18
|
+
end
|
19
|
+
|
20
|
+
flavor :open_source do
|
21
|
+
attribute :name, type: String, primary: true, required: true
|
22
|
+
end
|
23
|
+
|
7
24
|
attribute :admin, type: Boolean, default: false
|
8
25
|
attribute :public_key, type: String
|
26
|
+
attribute :private_key, type: [String, Boolean], default: false
|
27
|
+
end
|
28
|
+
|
29
|
+
has_many :organizations
|
30
|
+
|
31
|
+
class << self
|
32
|
+
#
|
33
|
+
# @see Base.each
|
34
|
+
#
|
35
|
+
def each(prefix = {}, &block)
|
36
|
+
users = collection(prefix)
|
37
|
+
|
38
|
+
# HEC/EC returns a slightly different response than OSC/CZ
|
39
|
+
if users.is_a?(Array)
|
40
|
+
users.each do |info|
|
41
|
+
name = URI.escape(info['user']['username'])
|
42
|
+
response = connection.get("/users/#{name}")
|
43
|
+
result = from_json(response, prefix)
|
44
|
+
|
45
|
+
block.call(result) if block
|
46
|
+
end
|
47
|
+
else
|
48
|
+
users.each do |_, path|
|
49
|
+
response = connection.get(path)
|
50
|
+
result = from_json(response, prefix)
|
51
|
+
|
52
|
+
block.call(result) if block
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Authenticate a user with the given +username+ and +password+.
|
59
|
+
#
|
60
|
+
# @note Requires Enterprise Chef
|
61
|
+
#
|
62
|
+
# @example Authenticate a user
|
63
|
+
# User.authenticate(username: 'user', password: 'pass')
|
64
|
+
# #=> { "status" => "linked", "user" => { ... } }
|
65
|
+
#
|
66
|
+
# @param [Hash] options
|
67
|
+
# the list of options to authenticate with
|
68
|
+
#
|
69
|
+
# @option options [String] username
|
70
|
+
# the username to authenticate with
|
71
|
+
# @option options [String] password
|
72
|
+
# the plain-text password to authenticate with
|
73
|
+
#
|
74
|
+
# @return [Hash]
|
75
|
+
# the parsed JSON response from the server
|
76
|
+
#
|
77
|
+
def authenticate(options = {})
|
78
|
+
connection.post('/authenticate_user', options)
|
79
|
+
end
|
9
80
|
end
|
10
81
|
end
|
11
82
|
end
|
data/lib/chef-api/schema.rb
CHANGED
@@ -13,7 +13,6 @@ module ChefAPI
|
|
13
13
|
attr_reader :attributes
|
14
14
|
|
15
15
|
attr_reader :ignored_attributes
|
16
|
-
attr_reader :transformations
|
17
16
|
|
18
17
|
#
|
19
18
|
# The list of defined validators for this schema.
|
@@ -28,15 +27,10 @@ module ChefAPI
|
|
28
27
|
def initialize(&block)
|
29
28
|
@attributes = {}
|
30
29
|
@ignored_attributes = {}
|
31
|
-
@
|
30
|
+
@flavor_attributes = {}
|
32
31
|
@validators = []
|
33
32
|
|
34
|
-
instance_eval(&block) if block
|
35
|
-
|
36
|
-
@attributes.freeze
|
37
|
-
@ignored_attributes.freeze
|
38
|
-
@transformations.freeze
|
39
|
-
@validators.freeze
|
33
|
+
unlock { instance_eval(&block) } if block
|
40
34
|
end
|
41
35
|
|
42
36
|
#
|
@@ -49,6 +43,45 @@ module ChefAPI
|
|
49
43
|
@primary_key ||= @attributes.first[0]
|
50
44
|
end
|
51
45
|
|
46
|
+
#
|
47
|
+
# Create a lazy-loaded block for a given flavor.
|
48
|
+
#
|
49
|
+
# @example Create a block for Enterprise Chef
|
50
|
+
# flavor :enterprise do
|
51
|
+
# attribute :custom_value
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# @param [Symbol] id
|
55
|
+
# the id of the flavor to target
|
56
|
+
# @param [Proc] block
|
57
|
+
# the block to capture
|
58
|
+
#
|
59
|
+
# @return [Proc]
|
60
|
+
# the given block
|
61
|
+
#
|
62
|
+
def flavor(id, &block)
|
63
|
+
@flavor_attributes[id] = block
|
64
|
+
block
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Load the flavor block for the given id.
|
69
|
+
#
|
70
|
+
# @param [Symbol] id
|
71
|
+
# the id of the flavor to target
|
72
|
+
#
|
73
|
+
# @return [true, false]
|
74
|
+
# true if the flavor existed and was evaluted, false otherwise
|
75
|
+
#
|
76
|
+
def load_flavor(id)
|
77
|
+
if block = @flavor_attributes[id]
|
78
|
+
unlock { instance_eval(&block) }
|
79
|
+
true
|
80
|
+
else
|
81
|
+
false
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
52
85
|
#
|
53
86
|
# DSL method for defining an attribute.
|
54
87
|
#
|
@@ -91,22 +124,27 @@ module ChefAPI
|
|
91
124
|
end
|
92
125
|
end
|
93
126
|
|
127
|
+
private
|
128
|
+
|
94
129
|
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
# @example Transform the +:bacon+ attribute onto the +:ham+ attribute
|
98
|
-
# transform :bacon, ham: true
|
99
|
-
#
|
100
|
-
# @example Transform an attribute with a complex transformation
|
101
|
-
# transform :bacon, ham: ->(value) { value.split('__', 2).last }
|
130
|
+
# @private
|
102
131
|
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
# the key-value pair of the transformations to make
|
132
|
+
# Helper method to duplicate and unfreeze all the attributes in the schema,
|
133
|
+
# yield control to the user for modification in the current context, and
|
134
|
+
# then re-freeze the variables for modification.
|
107
135
|
#
|
108
|
-
def
|
109
|
-
@
|
136
|
+
def unlock
|
137
|
+
@attributes = @attributes.dup
|
138
|
+
@ignored_attributes = @ignored_attributes.dup
|
139
|
+
@flavor_attributes = @flavor_attributes.dup
|
140
|
+
@validators = @validators.dup
|
141
|
+
|
142
|
+
yield
|
143
|
+
|
144
|
+
@attributes.freeze
|
145
|
+
@ignored_attributes.freeze
|
146
|
+
@flavor_attributes.freeze
|
147
|
+
@validators.freeze
|
110
148
|
end
|
111
149
|
end
|
112
150
|
end
|
data/lib/chef-api/version.rb
CHANGED
data/lib/chef-api.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
require 'json'
|
2
|
+
require 'logify'
|
2
3
|
require 'pathname'
|
3
4
|
require 'chef-api/version'
|
4
5
|
|
6
|
+
# Do not inflate JSON objects
|
7
|
+
JSON.create_id = nil
|
8
|
+
|
5
9
|
module ChefAPI
|
6
10
|
autoload :Boolean, 'chef-api/boolean'
|
7
11
|
autoload :Configurable, 'chef-api/configurable'
|
@@ -9,7 +13,6 @@ module ChefAPI
|
|
9
13
|
autoload :Defaults, 'chef-api/defaults'
|
10
14
|
autoload :Error, 'chef-api/errors'
|
11
15
|
autoload :ErrorCollection, 'chef-api/error_collection'
|
12
|
-
autoload :Logger, 'chef-api/logger'
|
13
16
|
autoload :Resource, 'chef-api/resource'
|
14
17
|
autoload :Schema, 'chef-api/schema'
|
15
18
|
autoload :Util, 'chef-api/util'
|
@@ -23,6 +26,28 @@ module ChefAPI
|
|
23
26
|
class << self
|
24
27
|
include ChefAPI::Configurable
|
25
28
|
|
29
|
+
#
|
30
|
+
# Set the log level.
|
31
|
+
#
|
32
|
+
# @example Set the log level to :info
|
33
|
+
# ChefAPI.log_level = :info
|
34
|
+
#
|
35
|
+
# @param [Symbol] level
|
36
|
+
# the log level to set
|
37
|
+
#
|
38
|
+
def log_level=(level)
|
39
|
+
Logify.level = level
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Get the current log level.
|
44
|
+
#
|
45
|
+
# @return [Symbol]
|
46
|
+
#
|
47
|
+
def log_level
|
48
|
+
Logify.level
|
49
|
+
end
|
50
|
+
|
26
51
|
#
|
27
52
|
# The source root of the ChefAPI gem. This is useful when requiring files
|
28
53
|
# that are relative to the root of the project.
|
@@ -67,10 +92,6 @@ module ChefAPI
|
|
67
92
|
end
|
68
93
|
end
|
69
94
|
|
70
|
-
require 'i18n'
|
71
|
-
I18n.enforce_available_locales = false
|
72
|
-
I18n.load_path << Dir[ChefAPI.root.join('locales', '*.yml').to_s]
|
73
|
-
|
74
95
|
# Load the initial default values
|
75
96
|
ChefAPI.setup
|
76
97
|
|
@@ -4,5 +4,59 @@ module ChefAPI
|
|
4
4
|
describe Resource::Client do
|
5
5
|
it_behaves_like 'a Chef API resource', :client,
|
6
6
|
update: { validator: true }
|
7
|
+
|
8
|
+
describe '.from_file' do
|
9
|
+
let(:private_key) do
|
10
|
+
<<-EOH.strip.gsub(/^ {10}/, '')
|
11
|
+
-----BEGIN RSA PRIVATE KEY-----
|
12
|
+
MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI
|
13
|
+
w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP
|
14
|
+
kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2
|
15
|
+
hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO
|
16
|
+
Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW
|
17
|
+
yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd
|
18
|
+
ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1
|
19
|
+
Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf
|
20
|
+
TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK
|
21
|
+
iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A
|
22
|
+
sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf
|
23
|
+
4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP
|
24
|
+
cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk
|
25
|
+
EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN
|
26
|
+
CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX
|
27
|
+
3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG
|
28
|
+
YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj
|
29
|
+
3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+
|
30
|
+
dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz
|
31
|
+
6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC
|
32
|
+
P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF
|
33
|
+
llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ
|
34
|
+
kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH
|
35
|
+
+vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ
|
36
|
+
NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s=
|
37
|
+
-----END RSA PRIVATE KEY-----
|
38
|
+
EOH
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:client) { described_class.from_file('/path/to/bacon.pem') }
|
42
|
+
|
43
|
+
before do
|
44
|
+
File.stub(:read).and_return(private_key)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'loads the client from the server' do
|
48
|
+
chef_server.create_client('bacon', validator: true)
|
49
|
+
|
50
|
+
expect(client.name).to eq('bacon')
|
51
|
+
expect(client.private_key).to eq(private_key)
|
52
|
+
expect(client.validator).to be_true
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'creates a new instance when the client does not exist' do
|
56
|
+
expect(client.name).to eq('bacon')
|
57
|
+
expect(client.validator).to be_false
|
58
|
+
expect(client.new_resource?).to be_true
|
59
|
+
end
|
60
|
+
end
|
7
61
|
end
|
8
62
|
end
|
data/spec/spec_helper.rb
CHANGED