kubeclient 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of kubeclient might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc17e4674c3ba30929ff7269036b8ece9c803d27
4
- data.tar.gz: 1d6e55bd1fdd2fd7f05e1984cf43e4622c550416
3
+ metadata.gz: 1c59006602c7c19f25b5fd0d136a5ee84e713a39
4
+ data.tar.gz: 9df86f3e7570f7af4c6cfa4d7100cfcd4c02b74c
5
5
  SHA512:
6
- metadata.gz: 17a5534c7be7404ff9e5b376d6c2571582fc6c6ac795301445bdd40361aa27029db856ef0367ce8d52f125fa47e8dc5c4b0c8ec3ab1c8347001e364a17542d41
7
- data.tar.gz: 7e847c215609634b3c9d15e961c872aaab6792a95e785d9b2aeb62891acd838d628f257688fa2ea4a81494129eb56e3510106234805dac7fe40004bdea7fd472
6
+ metadata.gz: 3d7f6d402db1e35486f753178d8fc228cc2eb5b0ed0a6d5adca43dde6b0edd8747b6633df8249bc6247f403e066b73625363864d6865b2758cdad2cebf3ea5f4
7
+ data.tar.gz: c0124a5a1477a18f3759ba51933ac92528967e1ddc68465777e94f19b67a0f18ff866b7c6a1dff5ac5d125433723e4ab43d68cd5ad3701dbdf8a98ccb0220d80
data/README.md CHANGED
@@ -38,6 +38,12 @@ Or without specifying version (it will be set by default to "v1")
38
38
  client = Kubeclient::Client.new 'http://localhost:8080/api/'
39
39
  ```
40
40
 
41
+ For A Group Api:
42
+
43
+ ```ruby
44
+ client = Kubeclient::Client.new('http://localhost:8080/apis/batch', 'v1')
45
+ ```
46
+
41
47
  Another option is to initialize the client with URI object:
42
48
 
43
49
  ```ruby
@@ -127,6 +133,8 @@ client = Kubeclient::Client.new 'https://localhost:8443/api/' , 'v1',
127
133
  auth_options: auth_options
128
134
  ```
129
135
 
136
+ You can find information about token in [this guide](http://kubernetes.io/docs/user-guide/accessing-the-cluster/) and in [this reference](http://kubernetes.io/docs/admin/authentication/).
137
+
130
138
  You can also use kubeclient with non-blocking sockets such as Celluloid::IO, see [here](https://github.com/httprb/http/wiki/Parallel-requests-with-Celluloid%3A%3AIO)
131
139
  for details. For example:
132
140
 
@@ -148,6 +156,49 @@ client = Kubeclient::Client.new('https://localhost:8443/api/',
148
156
  :http_proxy_uri => proxy_uri)
149
157
  ```
150
158
 
159
+ ### Discovery
160
+
161
+ Discovery from the kube-apiserver is done lazily on method calls so it would not change behavior.
162
+
163
+ It can also be done explicitly:
164
+ ```
165
+ client = Kubeclient::Client.new('http://localhost:8080/api', 'v1')
166
+ client.discover
167
+ ```
168
+
169
+ It is possible to check the status of discovery
170
+ ```
171
+ unless client.discovered
172
+ client.discover
173
+ end
174
+ ```
175
+
176
+ ### Kubeclient::Config
177
+
178
+ If you've been using `kubectl` and have a `.kube/config` file, you can auto-populate a config object using `Kubeclient::Config`:
179
+ ```ruby
180
+ config = Kubeclient::Config.read('/path/to/.kube/config')
181
+ ```
182
+
183
+ ...and then pass that object to `Kubeclient::Client`:
184
+
185
+ ```
186
+ Kubeclient::Client.new(
187
+ config.context.api_endpoint,
188
+ config.context.api_version,
189
+ {
190
+ ssl_options: config.context.ssl_options,
191
+ auth_options: config.context.auth_options
192
+ }
193
+ )
194
+ ```
195
+
196
+ You can also load your JSONified config in from an ENV variable (e.g. `KUBE_CONFIG`) like so:
197
+
198
+ ```
199
+ Kubeclient::Config.new(JSON.parse(ENV['KUBE_CONFIG']), nil)
200
+ ```
201
+
151
202
  ## Examples:
152
203
 
153
204
  #### Get all instances of a specific entity type
@@ -330,6 +381,28 @@ watcher.each do |line|
330
381
  end
331
382
  ```
332
383
 
384
+ #### Process a template
385
+ Returns a processed template containing a list of objects to create.
386
+ Input parameter - template (hash)
387
+ Besides its metadata, the template should include a list of objects to be processed and a list of parameters
388
+ to be substituted. Note that for a required parameter that does not provide a generated value, you must supply a value.
389
+
390
+ ```ruby
391
+ client.process_template template
392
+ ```
393
+
394
+ ## Upgrading
395
+
396
+ #### past version 1.2.0
397
+ Replace Specific Entity class references:
398
+ ```ruby
399
+ Kubeclient::Service
400
+ ```
401
+ with the generic
402
+ ```ruby
403
+ Kubeclient::Resource.new
404
+ ```
405
+ Where ever possible.
333
406
 
334
407
  ## Contributing
335
408
 
data/kubeclient.gemspec CHANGED
@@ -26,7 +26,6 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency 'vcr'
27
27
  spec.add_development_dependency 'rubocop', '= 0.30.0'
28
28
  spec.add_dependency 'rest-client'
29
- spec.add_dependency 'activesupport'
30
29
  spec.add_dependency 'recursive-open-struct', '= 1.0.0'
31
30
  spec.add_dependency 'http', '= 0.9.8'
32
31
  end
data/lib/kubeclient.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'kubeclient/version'
2
2
  require 'json'
3
3
  require 'rest-client'
4
- require 'active_support/inflector'
5
4
  require 'kubeclient/entity_list'
6
5
  require 'kubeclient/kube_exception'
7
6
  require 'kubeclient/watch_notice'
@@ -13,40 +12,20 @@ module Kubeclient
13
12
  # Kubernetes Client
14
13
  class Client
15
14
  include ClientMixin
16
- # Dynamically creating classes definitions (class Pod, class Service, etc.),
17
- # The classes are extending RecursiveOpenStruct.
18
- # This cancels the need to define the classes
19
- # manually on every new entity addition,
20
- # and especially since currently the class body is empty
21
- ENTITY_TYPES = %w(Pod Service ReplicationController Node Event Endpoint
22
- Namespace Secret ResourceQuota LimitRange PersistentVolume
23
- PersistentVolumeClaim ComponentStatus ServiceAccount).map do |et|
24
- clazz = Class.new(RecursiveOpenStruct) do
25
- def initialize(hash = nil, args = {})
26
- args.merge!(recurse_over_arrays: true)
27
- super(hash, args)
28
- end
29
- end
30
- [Kubeclient.const_set(et, clazz), et]
31
- end
32
-
33
- ClientMixin.define_entity_methods(ENTITY_TYPES)
34
-
15
+ # define a multipurpose resource class, available before discovery
16
+ ClientMixin.resource_class(Kubeclient, 'Resource')
35
17
  def initialize(
36
18
  uri,
37
19
  version = 'v1',
38
20
  **options
39
21
  )
40
22
  initialize_client(
23
+ Kubeclient,
41
24
  uri,
42
25
  '/api',
43
26
  version,
44
27
  options
45
28
  )
46
29
  end
47
-
48
- def all_entities
49
- retrieve_all_entities(ENTITY_TYPES)
50
- end
51
30
  end
52
31
  end
@@ -4,6 +4,8 @@ module Kubeclient
4
4
  # Common methods
5
5
  # this is mixed in by other gems
6
6
  module ClientMixin
7
+ ENTITY_METHODS = %w(get watch delete create update patch)
8
+
7
9
  DEFAULT_SSL_OPTIONS = {
8
10
  client_cert: nil,
9
11
  client_key: nil,
@@ -26,13 +28,22 @@ module Kubeclient
26
28
 
27
29
  DEFAULT_HTTP_PROXY_URI = nil
28
30
 
31
+ SEARCH_ARGUMENTS = {
32
+ 'labelSelector' => :label_selector,
33
+ 'fieldSelector' => :field_selector
34
+ }.freeze
35
+
36
+ WATCH_ARGUMENTS = { 'resourceVersion' => :resource_version }.merge!(SEARCH_ARGUMENTS).freeze
37
+
29
38
  attr_reader :api_endpoint
30
39
  attr_reader :ssl_options
31
40
  attr_reader :auth_options
32
41
  attr_reader :http_proxy_uri
33
42
  attr_reader :headers
43
+ attr_reader :discovered
34
44
 
35
45
  def initialize_client(
46
+ class_owner,
36
47
  uri,
37
48
  path,
38
49
  version,
@@ -44,6 +55,9 @@ module Kubeclient
44
55
  validate_auth_options(auth_options)
45
56
  handle_uri(uri, path)
46
57
 
58
+ @class_owner = class_owner
59
+ @entities = {}
60
+ @discovered = false
47
61
  @api_version = version
48
62
  @headers = {}
49
63
  @ssl_options = ssl_options
@@ -59,6 +73,28 @@ module Kubeclient
59
73
  end
60
74
  end
61
75
 
76
+ def method_missing(method_sym, *args, &block)
77
+ if discovery_needed?(method_sym)
78
+ discover
79
+ send(method_sym, *args, &block)
80
+ else
81
+ super
82
+ end
83
+ end
84
+
85
+ def respond_to_missing?(method_sym, include_private = false)
86
+ if discovery_needed?(method_sym)
87
+ discover
88
+ respond_to?(method_sym, include_private)
89
+ else
90
+ super
91
+ end
92
+ end
93
+
94
+ def discovery_needed?(method_sym)
95
+ !@discovered && ENTITY_METHODS.any? { |x| method_sym.to_s.start_with?(x) }
96
+ end
97
+
62
98
  def handle_exception
63
99
  yield
64
100
  rescue RestClient::Exception => e
@@ -71,11 +107,44 @@ module Kubeclient
71
107
  raise KubeException.new(e.http_code, err_message, e.response)
72
108
  end
73
109
 
110
+ def discover
111
+ @entities = {}
112
+ result = JSON.parse(handle_exception { rest_client.get(@headers) })
113
+ result['resources'].each do |resource|
114
+ next if resource['name'].include?('/')
115
+ entity = ClientMixin.parse_definition(resource['kind'], resource['name'])
116
+ @entities[entity.method_names[0]] = entity if entity
117
+ end
118
+ define_entity_methods
119
+ @discovered = true
120
+ end
121
+
122
+ def self.parse_definition(kind, name)
123
+ # "name": "componentstatuses", networkpolicies, endpoints
124
+ # "kind": "ComponentStatus" NetworkPolicy, Endpoints
125
+ # maintain pre group api compatibility for endpoints.
126
+ # See: https://github.com/kubernetes/kubernetes/issues/8115
127
+ kind = 'Endpoint' if kind == 'Endpoints'
128
+
129
+ prefix = kind[0..kind.rindex(/[A-Z]/)] # NetworkP
130
+ m = name.match(/^#{prefix.downcase}(.*)$/)
131
+ m && OpenStruct.new(
132
+ entity_type: kind, # ComponentStatus
133
+ resource_name: name, # componentstatuses
134
+ method_names: [
135
+ ClientMixin.underscore_entity(kind), # component_status
136
+ ClientMixin.underscore_entity(prefix) + m[1] # component_statuses
137
+ ]
138
+ )
139
+ end
140
+
74
141
  def handle_uri(uri, path)
75
142
  fail ArgumentError, 'Missing uri' unless uri
76
143
  @api_endpoint = (uri.is_a?(URI) ? uri : URI.parse(uri))
77
144
  @api_endpoint.path = path if @api_endpoint.path.empty?
78
145
  @api_endpoint.path = @api_endpoint.path.chop if @api_endpoint.path.end_with? '/'
146
+ components = @api_endpoint.path.to_s.split('/') # ["", "api"] or ["", "apis", batch]
147
+ @api_group = components.length > 2 ? components[2] + '/' : ''
79
148
  end
80
149
 
81
150
  def build_namespace_prefix(namespace)
@@ -84,51 +153,62 @@ module Kubeclient
84
153
 
85
154
  public
86
155
 
87
- def self.define_entity_methods(entity_types)
88
- entity_types.each do |klass, entity_type|
89
- entity_name = entity_type.underscore
90
- entity_name_plural = pluralize_entity(entity_name)
156
+ def self.resource_class(class_owner, entity_type)
157
+ class_owner.const_get(entity_type, false)
158
+ rescue NameError
159
+ class_owner.const_set(
160
+ entity_type,
161
+ Class.new(RecursiveOpenStruct) do
162
+ def initialize(hash = nil, args = {})
163
+ args[:recurse_over_arrays] = true
164
+ super(hash, args)
165
+ end
166
+ end
167
+ )
168
+ end
91
169
 
170
+ def define_entity_methods
171
+ @entities.values.each do |entity|
172
+ klass = ClientMixin.resource_class(@class_owner, entity.entity_type)
92
173
  # get all entities of a type e.g. get_nodes, get_pods, etc.
93
- define_method("get_#{entity_name_plural}") do |options = {}|
94
- get_entities(entity_type, klass, options)
174
+ define_singleton_method("get_#{entity.method_names[1]}") do |options = {}|
175
+ get_entities(entity.entity_type, klass, entity.resource_name, options)
95
176
  end
96
177
 
97
178
  # watch all entities of a type e.g. watch_nodes, watch_pods, etc.
98
- define_method("watch_#{entity_name_plural}") do |options = {}|
179
+ define_singleton_method("watch_#{entity.method_names[1]}") do |options = {}|
99
180
  # This method used to take resource_version as a param, so
100
181
  # this conversion is to keep backwards compatibility
101
182
  options = { resource_version: options } unless options.is_a?(Hash)
102
183
 
103
- watch_entities(entity_type, options)
184
+ watch_entities(entity.resource_name, options)
104
185
  end
105
186
 
106
187
  # get a single entity of a specific type by name
107
- define_method("get_#{entity_name}") do |name, namespace = nil|
108
- get_entity(entity_type, klass, name, namespace)
188
+ define_singleton_method("get_#{entity.method_names[0]}") do |name, namespace = nil|
189
+ get_entity(klass, entity.resource_name, name, namespace)
109
190
  end
110
191
 
111
- define_method("delete_#{entity_name}") do |name, namespace = nil|
112
- delete_entity(entity_type, name, namespace)
192
+ define_singleton_method("delete_#{entity.method_names[0]}") do |name, namespace = nil|
193
+ delete_entity(entity.resource_name, name, namespace)
113
194
  end
114
195
 
115
- define_method("create_#{entity_name}") do |entity_config|
116
- create_entity(entity_type, entity_config, klass)
196
+ define_singleton_method("create_#{entity.method_names[0]}") do |entity_config|
197
+ create_entity(entity.entity_type, entity.resource_name, entity_config, klass)
117
198
  end
118
199
 
119
- define_method("update_#{entity_name}") do |entity_config|
120
- update_entity(entity_type, entity_config)
200
+ define_singleton_method("update_#{entity.method_names[0]}") do |entity_config|
201
+ update_entity(entity.resource_name, entity_config)
121
202
  end
122
203
 
123
- define_method("patch_#{entity_name}") do |name, patch, namespace = nil|
124
- patch_entity(entity_type, name, patch, namespace)
204
+ define_singleton_method("patch_#{entity.method_names[0]}") do |name, patch, namespace = nil|
205
+ patch_entity(entity.resource_name, name, patch, namespace)
125
206
  end
126
207
  end
127
208
  end
128
209
 
129
- def self.pluralize_entity(entity_name)
130
- return entity_name + 's' if entity_name.end_with? 'quota'
131
- entity_name.pluralize
210
+ def self.underscore_entity(entity_name)
211
+ entity_name.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
132
212
  end
133
213
 
134
214
  def create_rest_client(path = nil)
@@ -158,17 +238,16 @@ module Kubeclient
158
238
  # :label_selector - a selector to restrict the list of returned objects by their labels.
159
239
  # :field_selector - a selector to restrict the list of returned objects by their fields.
160
240
  # :resource_version - shows changes that occur after that particular version of a resource.
161
- def watch_entities(entity_type, options = {})
241
+ def watch_entities(resource_name, options = {})
162
242
  ns = build_namespace_prefix(options[:namespace])
163
243
 
164
- path = "watch/#{ns}#{resource_name(entity_type.to_s)}"
244
+ path = "watch/#{ns}#{resource_name}"
165
245
  path += "/#{options[:name]}" if options[:name]
166
246
  uri = @api_endpoint.merge("#{@api_endpoint.path}/#{@api_version}/#{path}")
167
247
 
168
- params = options.slice(:label_selector, :field_selector, :resource_version)
169
- if params.any?
170
- uri.query = URI.encode_www_form(params.map { |k, v| [k.to_s.camelize(:lower), v] })
171
- end
248
+ params = {}
249
+ WATCH_ARGUMENTS.each { |k, v| params[k] = options[v] if options[v] }
250
+ uri.query = URI.encode_www_form(params) if params.any?
172
251
 
173
252
  Kubeclient::Common::WatchStream.new(uri, http_options(uri))
174
253
  end
@@ -177,15 +256,13 @@ module Kubeclient
177
256
  # :namespace - the namespace of the entity.
178
257
  # :label_selector - a selector to restrict the list of returned objects by their labels.
179
258
  # :field_selector - a selector to restrict the list of returned objects by their fields.
180
- def get_entities(entity_type, klass, options = {})
259
+ def get_entities(entity_type, klass, resource_name, options = {})
181
260
  params = {}
182
- [:label_selector, :field_selector].each do |p|
183
- params[p.to_s.camelize(:lower)] = options[p] if options[p]
184
- end
261
+ SEARCH_ARGUMENTS.each { |k, v| params[k] = options[v] if options[v] }
185
262
 
186
263
  ns_prefix = build_namespace_prefix(options[:namespace])
187
264
  response = handle_exception do
188
- rest_client[ns_prefix + resource_name(entity_type)]
265
+ rest_client[ns_prefix + resource_name]
189
266
  .get({ 'params' => params }.merge(@headers))
190
267
  end
191
268
 
@@ -203,25 +280,25 @@ module Kubeclient
203
280
  Kubeclient::Common::EntityList.new(entity_type, resource_version, collection)
204
281
  end
205
282
 
206
- def get_entity(entity_type, klass, name, namespace = nil)
283
+ def get_entity(klass, resource_name, name, namespace = nil)
207
284
  ns_prefix = build_namespace_prefix(namespace)
208
285
  response = handle_exception do
209
- rest_client[ns_prefix + resource_name(entity_type) + "/#{name}"]
286
+ rest_client[ns_prefix + resource_name + "/#{name}"]
210
287
  .get(@headers)
211
288
  end
212
289
  result = JSON.parse(response)
213
290
  new_entity(result, klass)
214
291
  end
215
292
 
216
- def delete_entity(entity_type, name, namespace = nil)
293
+ def delete_entity(resource_name, name, namespace = nil)
217
294
  ns_prefix = build_namespace_prefix(namespace)
218
295
  handle_exception do
219
- rest_client[ns_prefix + resource_name(entity_type) + "/#{name}"]
296
+ rest_client[ns_prefix + resource_name + "/#{name}"]
220
297
  .delete(@headers)
221
298
  end
222
299
  end
223
300
 
224
- def create_entity(entity_type, entity_config, klass)
301
+ def create_entity(entity_type, resource_name, entity_config, klass)
225
302
  # Duplicate the entity_config to a hash so that when we assign
226
303
  # kind and apiVersion, this does not mutate original entity_config obj.
227
304
  hash = entity_config.to_hash
@@ -234,36 +311,36 @@ module Kubeclient
234
311
  # TODO: #2 solution for
235
312
  # https://github.com/kubernetes/kubernetes/issues/8115
236
313
  if entity_type.eql? 'Endpoint'
237
- hash[:kind] = resource_name(entity_type).capitalize
314
+ hash[:kind] = 'Endpoints'
238
315
  else
239
316
  hash[:kind] = entity_type
240
317
  end
241
- hash[:apiVersion] = @api_version
242
- @headers['Content-Type'] = 'application/json'
318
+ hash[:apiVersion] = @api_group + @api_version
243
319
  response = handle_exception do
244
- rest_client[ns_prefix + resource_name(entity_type)]
245
- .post(hash.to_json, @headers)
320
+ rest_client[ns_prefix + resource_name]
321
+ .post(hash.to_json, { 'Content-Type' => 'application/json' }.merge(@headers))
246
322
  end
247
323
  result = JSON.parse(response)
248
324
  new_entity(result, klass)
249
325
  end
250
326
 
251
- def update_entity(entity_type, entity_config)
327
+ def update_entity(resource_name, entity_config)
252
328
  name = entity_config[:metadata][:name]
253
329
  ns_prefix = build_namespace_prefix(entity_config[:metadata][:namespace])
254
- @headers['Content-Type'] = 'application/json'
255
330
  handle_exception do
256
- rest_client[ns_prefix + resource_name(entity_type) + "/#{name}"]
257
- .put(entity_config.to_h.to_json, @headers)
331
+ rest_client[ns_prefix + resource_name + "/#{name}"]
332
+ .put(entity_config.to_h.to_json, { 'Content-Type' => 'application/json' }.merge(@headers))
258
333
  end
259
334
  end
260
335
 
261
- def patch_entity(entity_type, name, patch, namespace = nil)
336
+ def patch_entity(resource_name, name, patch, namespace = nil)
262
337
  ns_prefix = build_namespace_prefix(namespace)
263
- @headers['Content-Type'] = 'application/strategic-merge-patch+json'
264
338
  handle_exception do
265
- rest_client[ns_prefix + resource_name(entity_type) + "/#{name}"]
266
- .patch(patch.to_json, @headers)
339
+ rest_client[ns_prefix + resource_name + "/#{name}"]
340
+ .patch(
341
+ patch.to_json,
342
+ { 'Content-Type' => 'application/strategic-merge-patch+json' }.merge(@headers)
343
+ )
267
344
  end
268
345
  end
269
346
 
@@ -271,14 +348,17 @@ module Kubeclient
271
348
  klass.new(hash)
272
349
  end
273
350
 
274
- def retrieve_all_entities(entity_types)
275
- entity_types.each_with_object({}) do |(_, entity_type), result_hash|
351
+ def all_entities
352
+ discover unless @discovered
353
+ @entities.values.each_with_object({}) do |entity, result_hash|
276
354
  # method call for get each entities
277
355
  # build hash of entity name to array of the entities
278
- entity_name = ClientMixin.pluralize_entity entity_type.underscore
279
- method_name = "get_#{entity_name}"
280
- key_name = entity_type.underscore
281
- result_hash[key_name] = send(method_name)
356
+ method_name = "get_#{entity.method_names[1]}"
357
+ begin
358
+ result_hash[entity.method_names[0]] = send(method_name)
359
+ rescue KubeException
360
+ next # do not fail due to resources not supporting get
361
+ end
282
362
  end
283
363
  end
284
364
 
@@ -310,7 +390,12 @@ module Kubeclient
310
390
  end
311
391
 
312
392
  def proxy_url(kind, name, port, namespace = '')
313
- entity_name_plural = ClientMixin.pluralize_entity(kind.to_s)
393
+ discover unless @discovered
394
+ entity_name_plural = if %w(services pods nodes).include?(kind.to_s)
395
+ kind.to_s
396
+ else
397
+ @entities[kind.to_s].resource_name
398
+ end
314
399
  ns_prefix = build_namespace_prefix(namespace)
315
400
  # TODO: Change this once services supports the new scheme
316
401
  if entity_name_plural == 'pods'
@@ -320,19 +405,24 @@ module Kubeclient
320
405
  end
321
406
  end
322
407
 
323
- def resource_name(entity_type)
324
- ClientMixin.pluralize_entity entity_type.downcase
408
+ def process_template(template)
409
+ ns_prefix = build_namespace_prefix(template[:metadata][:namespace])
410
+ response = handle_exception do
411
+ rest_client[ns_prefix + 'processedtemplates']
412
+ .post(template.to_h.to_json, { 'Content-Type' => 'application/json' }.merge(@headers))
413
+ end
414
+ JSON.parse(response)
325
415
  end
326
416
 
327
417
  def api_valid?
328
418
  result = api
329
- result.is_a?(Hash) && (result['versions'] || []).include?(@api_version)
419
+ result.is_a?(Hash) && (result['versions'] || []).any? do |group|
420
+ @api_group.empty? ? group.include?(@api_version) : group['version'] == (@api_version)
421
+ end
330
422
  end
331
423
 
332
424
  def api
333
- response = handle_exception do
334
- create_rest_client.get(@headers)
335
- end
425
+ response = handle_exception { create_rest_client.get(@headers) }
336
426
  JSON.parse(response)
337
427
  end
338
428