kubeclient 3.0.0 → 3.1.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: e9aaeb2002708298a57d829ccce3530a4233de62
4
- data.tar.gz: 4343990defde5ef36719ccbf02936b92e7e1be5c
3
+ metadata.gz: ad5e0d0d632be2585068c14cf2eb218e20788c83
4
+ data.tar.gz: f7b002dcb8a7a49381b3bdbe8e6eaf2abdbe1f4d
5
5
  SHA512:
6
- metadata.gz: 928f8df41783e2eb13c65536de2ad3270f3ed3fcc95459d25fcb21a66a6e86b0f279a9c238cddb7196dc82bd7c9cc7dd42a778f208ee56397e149a4c0f048f3c
7
- data.tar.gz: 9a541d45aba922c4ab24196bd3d0cb755a46ae5bd276436510fa66e60cdc6c60056eba4501152036751ec5cd8ec3ec8c0d254687c54b6ba532ac18812634a06b
6
+ metadata.gz: 0bec0e053d54fa34c6b058c071b55e681d0c97497808ba7e23703dcfde1dff5e86be185a2b3cf0c1c834b50857b11298ff524f14ed42c2145d18d859b85924c5
7
+ data.tar.gz: 5f2d7cb7770b4e7d3414b468704db641929eafde9452c60a863ab7d542cb3ea9fc1e35f8d2cddb3f85ccf02eb8a1dd078503748822e2ba7db3b9383210788cfe
@@ -4,6 +4,7 @@ rvm:
4
4
  - "2.3.0"
5
5
  - "2.4.0"
6
6
  - "2.5.0"
7
+ - "2.6.0-preview1"
7
8
  sudo: false
8
9
  cache: bundler
9
10
  script: bundle exec rake $TASK
@@ -2,15 +2,28 @@
2
2
 
3
3
  Notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
5
+ Kubeclient release versioning follows [SemVer](https://semver.org/).
5
6
 
6
- ## 3.0.0 - 2018-02-01
7
+ ## 3.1.0 - 2018-05-27
8
+
9
+ ### Fixed
10
+ - Fixed watch `.finish` sometimes caused `HTTP::ConnectionError` exception from the reading loop (#315).
11
+
12
+ ### Added
13
+ - `get_pod_log` now has `timestamps`, `since_time` (#319) and `tail_lines` (#326) params.
14
+ - `Kubeclient::Config::Context#namespace` now set, if present in kubeconfig file (#308).
15
+ - Improved README directions for authenticating within a kubernetes cluster (#316).
16
+ - `Kubeclient::GoogleApplicationDefaultCredentials` helper for Google application default credentials (#213). Needs `googleauth` gem.
17
+ - New `as: :parsed` and `as: :parsed_symbolized` formats (#306).
18
+ - Allow setting default `as:` format for the whole client (#299, #305).
19
+ - Relaxed `recursive-open-struct` dependency to allow 1.1+ as well (#313).
20
+
21
+ ## 3.0.0 - 2018-02-04
7
22
  ### Removed
8
23
  - Dropped entity classes (`Kubeclient::Pod` etc.), only `Kubeclient::Resource` exists now (#292, #288).
9
24
  - Ruby 2.0, 2.1 no longer supported (#253, #291).
10
25
 
11
26
  ### Fixed
12
- - Watch results are now `RecursiveOpenStruct` inside arrays too (#279).
13
- - Fixed watch `.finish` sometimes caused `Errno::EBADF` exception from the reading loop (#280).
14
27
  - Added missing singular `get_security_context_constraint`, fixed `get_security_context_constraints` to mean plural (#261).
15
28
  - Fixed `@http_proxy_uri` undefined warning (#261).
16
29
  - Documentation fixes & improvements (#225, #229, #243, #296).
@@ -28,6 +41,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
28
41
  - `update_*`, `delete_*`, `patch_*` now all return `RecursiveOpenStruct` consistently (#290).
29
42
  - Many dependencies bumped (#204, #231, #253, #269).
30
43
 
44
+ ## 2.5.2 - 2018-02-04
45
+ - Watch results are now `RecursiveOpenStruct` inside arrays too (#279).
46
+ - Fixed watch `.finish` sometimes caused `Errno::EBADF` exception from the reading loop (#280).
47
+ - Easing dependency version (#287, #301)
48
+
31
49
  ## 2.5.1 - 2017-10-12
32
50
  No changes since 2.5.0, fixed packaging mistake.
33
51
 
data/README.md CHANGED
@@ -134,23 +134,61 @@ client = Kubeclient::Client.new(
134
134
  )
135
135
  ```
136
136
 
137
- If you are running your app using kubeclient inside a Kubernetes cluster, then you can have a bearer token file
138
- mounted inside your pod by using a
139
- [Service Account](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/design/service_accounts.md). This
140
- will mount a bearer token [secret](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/design/secrets.md)
141
- a/ `/var/run/secrets/kubernetes.io/serviceaccount/token` (see [here](https://github.com/GoogleCloudPlatform/kubernetes/pull/7101)
142
- for more details). For example:
137
+ #### Inside a Kubernetes cluster
138
+
139
+ The [recommended way to locate the API server](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod) within the pod is with the `kubernetes.default.svc` DNS name, which resolves to a Service IP which in turn will be routed to an API server.
140
+
141
+ The recommended way to authenticate to the API server is with a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/). kube-system associates a pod with a service account and a bearer token for that service account is placed into the filesystem tree of each container in that pod at `/var/run/secrets/kubernetes.io/serviceaccount/token`.
142
+
143
+ If available, a certificate bundle is placed into the filesystem tree of each container at `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`, and should be used to verify the serving certificate of the API server.
144
+
145
+ For example:
143
146
 
144
147
  ```ruby
145
148
  auth_options = {
146
149
  bearer_token_file: '/var/run/secrets/kubernetes.io/serviceaccount/token'
147
150
  }
151
+ ssl_options = {}
152
+ if File.exist?("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
153
+ ssl_options[:ca_file] = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
154
+ end
155
+ client = Kubeclient::Client.new(
156
+ 'https://kubernetes.default.svc',
157
+ 'v1',
158
+ auth_options: auth_options,
159
+ ssl_options: ssl_options
160
+ )
161
+ ```
162
+
163
+ Finally, the default namespace to be used for namespaced API operations is placed in a file at `/var/run/secrets/kubernetes.io/serviceaccount/namespace` in each container. It is recommended that you use this namespace when issuing API commands below.
164
+
165
+ ```ruby
166
+ namespace = File.read('/var/run/secrets/kubernetes.io/serviceaccount/namespace')
167
+ ```
168
+ You can find information about tokens in [this guide](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod) and in [this reference](http://kubernetes.io/docs/admin/authentication/).
169
+
170
+ #### Google's Application Default Credentials
171
+
172
+ On Google Compute Engine, Google App Engine, or Google Cloud Functions, as well as `gcloud`-configured systems
173
+ with [application default credentials](https://developers.google.com/identity/protocols/application-default-credentials),
174
+ you can use the token provider to authorize `kubeclient`.
175
+
176
+ This requires the [`googleauth` gem](https://github.com/google/google-auth-library-ruby) that is _not_ included in
177
+ `kubeclient` dependencies so you should add it to your bundle.
178
+
179
+ ```ruby
180
+ require 'googleauth'
181
+
182
+ auth_options = {
183
+ bearer_token: Kubeclient::GoogleApplicationDefaultCredentials.token
184
+ }
148
185
  client = Kubeclient::Client.new(
149
186
  'https://localhost:8443/api/', 'v1', auth_options: auth_options
150
187
  )
151
188
  ```
152
189
 
153
- You can find information about tokens in [this guide](http://kubernetes.io/docs/user-guide/accessing-the-cluster/) and in [this reference](http://kubernetes.io/docs/admin/authentication/).
190
+ Note that this token is good for one hour. If your code runs for longer than that, you should plan to
191
+ acquire a new one.
154
192
 
155
193
  ### Non-blocking IO
156
194
 
@@ -249,6 +287,18 @@ You can also load your JSONified config in from an ENV variable (e.g. `KUBE_CONF
249
287
  Kubeclient::Config.new(JSON.parse(ENV['KUBE_CONFIG']), nil)
250
288
  ```
251
289
 
290
+ #### namespace
291
+
292
+ Additionally, the `config.context` object will contain a `namespace` attribute, if it was defined in the file.
293
+ It is recommended that you use this namespace when issuing API commands below.
294
+ This is the same behavior that is implemented by `kubectl` command.
295
+
296
+ You can read it as follows:
297
+
298
+ ```ruby
299
+ puts config.context.namespace
300
+ ```
301
+
252
302
  ### Supported kubernetes versions
253
303
 
254
304
  For 1.1 only the core api v1 is supported, all api groups are supported in later versions.
@@ -297,13 +347,26 @@ Note - Kubernetes doesn't work with the uid, but rather with the 'name' property
297
347
  Querying with uid causes 404.
298
348
 
299
349
  #### Getting raw responses
300
- By passing `as: :raw`, the response from the client is given as a string, which is the raw JSON body from openshift:
350
+
351
+ To avoid overhead from parsing and building `RecursiveOpenStruct` objects for each reply, pass the `as: :raw` option when initializing `Kubeclient::Client` or when calling `get_` / `watch_` methods.
352
+ The result can then be printed, or searched with a regex, or parsed via `JSON.parse(r)`.
353
+
354
+ ```ruby
355
+ client = Kubeclient::Client.new(as: :raw)
356
+ ```
357
+
358
+ or
301
359
 
302
360
  ```ruby
303
361
  pods = client.get_pods as: :raw
304
362
  node = client.get_node "127.0.0.1", as: :raw
305
363
  ```
306
364
 
365
+ Other formats are:
366
+ - `:ros` (default) for `RecursiveOpenStruct`
367
+ - `:parsed` for `JSON.parse`
368
+ - `:parsed_symbolized` for `JSON.parse(..., symbolize_names: true)`
369
+
307
370
  #### Delete an entity (by name)
308
371
 
309
372
  For example: `delete_pod "pod name"` , `delete_replication_controller "rc name"`, `delete_node "node name"`, `delete_secret "secret name"`
@@ -402,8 +465,6 @@ It is possible to interrupt the watcher from another thread with:
402
465
  watcher.finish
403
466
  ```
404
467
 
405
- Pass `as: :raw` to `watch_*` get raw replies.
406
-
407
468
  #### Watch events for a particular object
408
469
  You can use the `field_selector` option as part of the watch methods.
409
470
 
@@ -453,6 +514,19 @@ client.get_pod_log('pod-name', 'default', previous: true)
453
514
  # => "..."
454
515
  ```
455
516
 
517
+ Kubernetes can add timestamps to every log line or filter by lines time:
518
+ ```ruby
519
+ client.get_pod_log('pod-name', 'default', timestamps: true, since_time: '2018-04-27T18:30:17.480321984Z')
520
+ # => "..."
521
+ ```
522
+ `since_time` can be a a `Time`, `DateTime` or `String` formatted according to RFC3339
523
+
524
+ Kubernetes can fetch a specific number of lines from the end of the logs:
525
+ ```ruby
526
+ client.get_pod_log('pod-name', 'default', tail_lines: 10)
527
+ # => "..."
528
+ ```
529
+
456
530
  You can also watch the logs of a pod to get a stream of data:
457
531
 
458
532
  ```ruby
@@ -476,6 +550,7 @@ client.process_template template
476
550
 
477
551
  ## Upgrading
478
552
 
553
+ Kubeclient release versioning follows [SemVer](https://semver.org/).
479
554
  See [CHANGELOG.md](CHANGELOG.md) for full changelog.
480
555
 
481
556
  #### past version 3.0
@@ -27,7 +27,9 @@ Gem::Specification.new do |spec|
27
27
  spec.add_development_dependency 'webmock', '~> 3.0.1'
28
28
  spec.add_development_dependency 'vcr'
29
29
  spec.add_development_dependency 'rubocop', '= 0.49.1'
30
+ spec.add_development_dependency 'googleauth', '~> 0.5.1'
31
+
30
32
  spec.add_dependency 'rest-client', '~> 2.0'
31
- spec.add_dependency 'recursive-open-struct', '~> 1.0.4'
33
+ spec.add_dependency 'recursive-open-struct', '~> 1.0', '>= 1.0.4'
32
34
  spec.add_dependency 'http', '~> 2.2.2'
33
35
  end
@@ -4,12 +4,12 @@ require 'rest-client'
4
4
  require 'kubeclient/common'
5
5
  require 'kubeclient/config'
6
6
  require 'kubeclient/entity_list'
7
+ require 'kubeclient/google_application_default_credentials'
7
8
  require 'kubeclient/http_error'
8
9
  require 'kubeclient/missing_kind_compatibility'
9
10
  require 'kubeclient/resource'
10
11
  require 'kubeclient/resource_not_found_error'
11
12
  require 'kubeclient/version'
12
- require 'kubeclient/watch_notice'
13
13
  require 'kubeclient/watch_stream'
14
14
 
15
15
  module Kubeclient
@@ -1,5 +1,6 @@
1
1
  require 'json'
2
2
  require 'rest-client'
3
+
3
4
  module Kubeclient
4
5
  # Common methods
5
6
  # this is mixed in by other gems
@@ -56,7 +57,8 @@ module Kubeclient
56
57
  auth_options: DEFAULT_AUTH_OPTIONS,
57
58
  socket_options: DEFAULT_SOCKET_OPTIONS,
58
59
  timeouts: DEFAULT_TIMEOUTS,
59
- http_proxy_uri: DEFAULT_HTTP_PROXY_URI
60
+ http_proxy_uri: DEFAULT_HTTP_PROXY_URI,
61
+ as: :ros
60
62
  )
61
63
  validate_auth_options(auth_options)
62
64
  handle_uri(uri, path)
@@ -72,6 +74,7 @@ module Kubeclient
72
74
  # @timeouts[:foo] == nil resulting in infinite timeout.
73
75
  @timeouts = DEFAULT_TIMEOUTS.merge(timeouts)
74
76
  @http_proxy_uri = http_proxy_uri ? http_proxy_uri.to_s : nil
77
+ @as = as
75
78
 
76
79
  if auth_options[:bearer_token]
77
80
  bearer_token(@auth_options[:bearer_token])
@@ -242,7 +245,11 @@ module Kubeclient
242
245
  WATCH_ARGUMENTS.each { |k, v| params[k] = options[v] if options[v] }
243
246
  uri.query = URI.encode_www_form(params) if params.any?
244
247
 
245
- Kubeclient::Common::WatchStream.new(uri, http_options(uri), as: options[:as] || :ros)
248
+ Kubeclient::Common::WatchStream.new(
249
+ uri,
250
+ http_options(uri),
251
+ formatter: ->(value) { format_response(options[:as] || @as, value) }
252
+ )
246
253
  end
247
254
 
248
255
  # Accepts the following options:
@@ -261,19 +268,7 @@ module Kubeclient
261
268
  rest_client[ns_prefix + resource_name]
262
269
  .get({ 'params' => params }.merge(@headers))
263
270
  end
264
- return response.body if options[:as] == :raw
265
-
266
- result = JSON.parse(response)
267
-
268
- resource_version =
269
- result.fetch('resourceVersion') do
270
- result.fetch('metadata', {}).fetch('resourceVersion', nil)
271
- end
272
-
273
- # result['items'] might be nil due to https://github.com/kubernetes/kubernetes/issues/13096
274
- collection = result['items'].to_a.map { |item| Kubeclient::Resource.new(item) }
275
-
276
- Kubeclient::Common::EntityList.new(entity_type, resource_version, collection)
271
+ format_response(options[:as] || @as, response.body, entity_type)
277
272
  end
278
273
 
279
274
  # Accepts the following options:
@@ -286,7 +281,7 @@ module Kubeclient
286
281
  rest_client[ns_prefix + resource_name + "/#{name}"]
287
282
  .get(@headers)
288
283
  end
289
- format_response(options[:as], response)
284
+ format_response(options[:as] || @as, response.body)
290
285
  end
291
286
 
292
287
  # delete_options are passed as a JSON payload in the delete request
@@ -305,7 +300,7 @@ module Kubeclient
305
300
  )
306
301
  )
307
302
  end
308
- format_response(:ros, response)
303
+ format_response(@as, response.body)
309
304
  end
310
305
 
311
306
  def create_entity(entity_type, resource_name, entity_config)
@@ -326,7 +321,7 @@ module Kubeclient
326
321
  rest_client[ns_prefix + resource_name]
327
322
  .post(hash.to_json, { 'Content-Type' => 'application/json' }.merge(@headers))
328
323
  end
329
- format_response(:ros, response)
324
+ format_response(@as, response.body)
330
325
  end
331
326
 
332
327
  def update_entity(resource_name, entity_config)
@@ -336,7 +331,7 @@ module Kubeclient
336
331
  rest_client[ns_prefix + resource_name + "/#{name}"]
337
332
  .put(entity_config.to_h.to_json, { 'Content-Type' => 'application/json' }.merge(@headers))
338
333
  end
339
- format_response(:ros, response)
334
+ format_response(@as, response.body)
340
335
  end
341
336
 
342
337
  def patch_entity(resource_name, name, patch, namespace = nil)
@@ -348,7 +343,7 @@ module Kubeclient
348
343
  { 'Content-Type' => 'application/strategic-merge-patch+json' }.merge(@headers)
349
344
  )
350
345
  end
351
- format_response(:ros, response)
346
+ format_response(@as, response.body)
352
347
  end
353
348
 
354
349
  def all_entities(options = {})
@@ -365,10 +360,15 @@ module Kubeclient
365
360
  end
366
361
  end
367
362
 
368
- def get_pod_log(pod_name, namespace, container: nil, previous: false)
363
+ def get_pod_log(pod_name, namespace,
364
+ container: nil, previous: false,
365
+ timestamps: false, since_time: nil, tail_lines: nil)
369
366
  params = {}
370
367
  params[:previous] = true if previous
371
368
  params[:container] = container if container
369
+ params[:timestamps] = timestamps if timestamps
370
+ params[:sinceTime] = format_datetime(since_time) if since_time
371
+ params[:tailLines] = tail_lines if tail_lines
372
372
 
373
373
  ns = build_namespace_prefix(namespace)
374
374
  handle_exception do
@@ -389,7 +389,7 @@ module Kubeclient
389
389
  uri.path += "/#{@api_version}/#{ns}pods/#{pod_name}/log"
390
390
  uri.query = URI.encode_www_form(params)
391
391
 
392
- Kubeclient::Common::WatchStream.new(uri, http_options(uri), as: :raw)
392
+ Kubeclient::Common::WatchStream.new(uri, http_options(uri), formatter: ->(value) { value })
393
393
  end
394
394
 
395
395
  def proxy_url(kind, name, port, namespace = '')
@@ -432,11 +432,45 @@ module Kubeclient
432
432
 
433
433
  private
434
434
 
435
- def format_response(as, response)
436
- return response.body if as == :raw
435
+ # Format ditetime according to RFC3339
436
+ def format_datetime(value)
437
+ case value
438
+ when DateTime, Time
439
+ value.strftime('%FT%T.%9N%:z')
440
+ when String
441
+ value
442
+ else
443
+ raise ArgumentError, "unsupported type '#{value.class}' of time value '#{value}'"
444
+ end
445
+ end
446
+
447
+ def format_response(as, body, list_type = nil)
448
+ case as
449
+ when :raw
450
+ body
451
+ when :parsed
452
+ JSON.parse(body)
453
+ when :parsed_symbolized
454
+ JSON.parse(body, symbolize_names: true)
455
+ when :ros
456
+ result = JSON.parse(body)
457
+
458
+ if list_type
459
+ resource_version =
460
+ result.fetch('resourceVersion') do
461
+ result.fetch('metadata', {}).fetch('resourceVersion', nil)
462
+ end
463
+
464
+ # result['items'] might be nil due to https://github.com/kubernetes/kubernetes/issues/13096
465
+ collection = result['items'].to_a.map { |item| Kubeclient::Resource.new(item) }
437
466
 
438
- result = JSON.parse(response)
439
- Kubeclient::Resource.new(result)
467
+ Kubeclient::Common::EntityList.new(list_type, resource_version, collection)
468
+ else
469
+ Kubeclient::Resource.new(result)
470
+ end
471
+ else
472
+ raise ArgumentError, "Unsupported format #{as.inspect}"
473
+ end
440
474
  end
441
475
 
442
476
  def load_entities
@@ -7,13 +7,14 @@ module Kubeclient
7
7
  class Config
8
8
  # Kubernetes client configuration context class
9
9
  class Context
10
- attr_reader :api_endpoint, :api_version, :ssl_options, :auth_options
10
+ attr_reader :api_endpoint, :api_version, :ssl_options, :auth_options, :namespace
11
11
 
12
- def initialize(api_endpoint, api_version, ssl_options, auth_options)
12
+ def initialize(api_endpoint, api_version, ssl_options, auth_options, namespace)
13
13
  @api_endpoint = api_endpoint
14
14
  @api_version = api_version
15
15
  @ssl_options = ssl_options
16
16
  @auth_options = auth_options
17
+ @namespace = namespace
17
18
  end
18
19
  end
19
20
 
@@ -32,7 +33,7 @@ module Kubeclient
32
33
  end
33
34
 
34
35
  def context(context_name = nil)
35
- cluster, user = fetch_context(context_name || @kcfg['current-context'])
36
+ cluster, user, namespace = fetch_context(context_name || @kcfg['current-context'])
36
37
 
37
38
  ca_cert_data = fetch_cluster_ca_data(cluster)
38
39
  client_cert_data = fetch_user_cert_data(user)
@@ -58,7 +59,7 @@ module Kubeclient
58
59
  ssl_options[:client_key] = OpenSSL::PKey.read(client_key_data)
59
60
  end
60
61
 
61
- Context.new(cluster['server'], @kcfg['apiVersion'], ssl_options, auth_options)
62
+ Context.new(cluster['server'], @kcfg['apiVersion'], ssl_options, auth_options, namespace)
62
63
  end
63
64
 
64
65
  private
@@ -84,7 +85,9 @@ module Kubeclient
84
85
  break x['user'] if x['name'] == context['user']
85
86
  end || {}
86
87
 
87
- [cluster, user]
88
+ namespace = context['namespace']
89
+
90
+ [cluster, user, namespace]
88
91
  end
89
92
 
90
93
  def fetch_cluster_ca_data(cluster)
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kubeclient
4
+ # Get a bearer token from the Google's application default credentials.
5
+ class GoogleApplicationDefaultCredentials
6
+ class << self
7
+ def token
8
+ require 'googleauth'
9
+ scopes = ['https://www.googleapis.com/auth/cloud-platform']
10
+ authorization = Google::Auth.get_application_default(scopes)
11
+ authorization.apply({})
12
+ authorization.access_token
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,4 +1,4 @@
1
1
  # Kubernetes REST-API Client
2
2
  module Kubeclient
3
- VERSION = '3.0.0'.freeze
3
+ VERSION = '3.1.0'.freeze
4
4
  end
@@ -4,11 +4,11 @@ module Kubeclient
4
4
  module Common
5
5
  # HTTP Stream used to watch changes on entities
6
6
  class WatchStream
7
- def initialize(uri, http_options, as:)
7
+ def initialize(uri, http_options, formatter:)
8
8
  @uri = uri
9
9
  @http_client = nil
10
10
  @http_options = http_options
11
- @as = as
11
+ @formatter = formatter
12
12
  end
13
13
 
14
14
  def each
@@ -24,16 +24,10 @@ module Kubeclient
24
24
  response.body.each do |chunk|
25
25
  buffer << chunk
26
26
  while (line = buffer.slice!(/.+\n/))
27
- result =
28
- case @as
29
- when :ros then WatchNotice.new(JSON.parse(line))
30
- when :raw then line.chomp
31
- else raise NotImplementedError, "Unsupported as #{@as.inspect}"
32
- end
33
- yield(result)
27
+ yield @formatter.call(line.chomp)
34
28
  end
35
29
  end
36
- rescue IOError, Errno::EBADF
30
+ rescue StandardError
37
31
  raise unless @finished
38
32
  end
39
33
 
@@ -2,6 +2,14 @@ require_relative 'test_helper'
2
2
 
3
3
  # Unit tests for the common module
4
4
  class CommonTest < MiniTest::Test
5
+ class ClientStub
6
+ include Kubeclient::ClientMixin
7
+ end
8
+
9
+ def client
10
+ @client ||= ClientStub.new
11
+ end
12
+
5
13
  def test_underscore_entity
6
14
  %w[
7
15
  Pod pod
@@ -29,4 +37,22 @@ class CommonTest < MiniTest::Test
29
37
  assert_equal(Kubeclient::ClientMixin.underscore_entity(singular), plural)
30
38
  end
31
39
  end
40
+
41
+ def test_format_datetime_with_string
42
+ value = '2018-04-27T18:30:17.480321984Z'
43
+ formatted = client.send(:format_datetime, value)
44
+ assert_equal(formatted, value)
45
+ end
46
+
47
+ def test_format_datetime_with_datetime
48
+ value = DateTime.new(2018, 4, 30, 19, 20, 33)
49
+ formatted = client.send(:format_datetime, value)
50
+ assert_equal(formatted, '2018-04-30T19:20:33.000000000+00:00')
51
+ end
52
+
53
+ def test_format_datetime_with_time
54
+ value = Time.new(2018, 4, 30, 19, 20, 33, 0)
55
+ formatted = client.send(:format_datetime, value)
56
+ assert_equal(formatted, '2018-04-30T19:20:33.000000000+00:00')
57
+ end
32
58
  end
@@ -44,6 +44,7 @@ class KubeclientConfigTest < MiniTest::Test
44
44
  def check_context(context, ssl: true)
45
45
  assert_equal('https://localhost:8443', context.api_endpoint)
46
46
  assert_equal('v1', context.api_version)
47
+ assert_equal('default', context.namespace)
47
48
  if ssl
48
49
  assert_equal(OpenSSL::SSL::VERIFY_PEER, context.ssl_options[:verify_ssl])
49
50
  assert_kind_of(OpenSSL::X509::Store, context.ssl_options[:cert_store])
@@ -0,0 +1,15 @@
1
+ require_relative 'test_helper'
2
+ require 'googleauth'
3
+
4
+ # Unit tests for the ApplicationDefaultCredentials token provider
5
+ class GoogleApplicationDefaultCredentialsTest < MiniTest::Test
6
+ def test_token
7
+ auth = Minitest::Mock.new
8
+ auth.expect(:apply, nil, [{}])
9
+ auth.expect(:access_token, 'valid_token')
10
+
11
+ Google::Auth.stub(:get_application_default, auth) do
12
+ assert_equal('valid_token', Kubeclient::GoogleApplicationDefaultCredentials.token)
13
+ end
14
+ end
15
+ end
@@ -43,8 +43,7 @@ class KubeclientTest < MiniTest::Test
43
43
  def test_pass_proxy
44
44
  uri = URI::HTTP.build(host: 'localhost', port: 8080)
45
45
  proxy_uri = URI::HTTP.build(host: 'myproxyhost', port: 8888)
46
- stub_request(:get, %r{/api/v1$})
47
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
46
+ stub_core_api_list
48
47
 
49
48
  client = Kubeclient::Client.new(uri, http_proxy_uri: proxy_uri)
50
49
  rest_client = client.rest_client
@@ -56,8 +55,7 @@ class KubeclientTest < MiniTest::Test
56
55
  end
57
56
 
58
57
  def test_exception
59
- stub_request(:get, %r{/api/v1$})
60
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
58
+ stub_core_api_list
61
59
  stub_request(:post, %r{/services})
62
60
  .to_return(body: open_test_file('namespace_exception.json'), status: 409)
63
61
 
@@ -99,7 +97,6 @@ class KubeclientTest < MiniTest::Test
99
97
  stub_request(:get, 'http://localhost:8080/api')
100
98
  .to_return(status: 200, body: open_test_file('versions_list.json'))
101
99
 
102
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
103
100
  response = client.api
104
101
  assert_includes(response, 'versions')
105
102
  end
@@ -178,13 +175,10 @@ class KubeclientTest < MiniTest::Test
178
175
  end
179
176
 
180
177
  def test_nonjson_exception
181
- stub_request(:get, %r{/api/v1$})
182
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
178
+ stub_core_api_list
183
179
  stub_request(:get, %r{/servic})
184
180
  .to_return(body: open_test_file('service_illegal_json_404.json'), status: 404)
185
181
 
186
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
187
-
188
182
  exception = assert_raises(Kubeclient::ResourceNotFoundError) do
189
183
  client.get_services
190
184
  end
@@ -194,13 +188,10 @@ class KubeclientTest < MiniTest::Test
194
188
  end
195
189
 
196
190
  def test_nonjson_exception_raw
197
- stub_request(:get, %r{/api/v1$})
198
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
191
+ stub_core_api_list
199
192
  stub_request(:get, %r{/servic})
200
193
  .to_return(body: open_test_file('service_illegal_json_404.json'), status: 404)
201
194
 
202
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
203
-
204
195
  exception = assert_raises(Kubeclient::ResourceNotFoundError) do
205
196
  client.get_services(as: :raw)
206
197
  end
@@ -210,12 +201,9 @@ class KubeclientTest < MiniTest::Test
210
201
  end
211
202
 
212
203
  def test_entity_list
213
- stub_request(:get, %r{/api/v1$})
214
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
215
- stub_request(:get, %r{/services})
216
- .to_return(body: open_test_file('entity_list.json'), status: 200)
204
+ stub_core_api_list
205
+ stub_get_services
217
206
 
218
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
219
207
  services = client.get_services
220
208
 
221
209
  refute_empty(services)
@@ -229,12 +217,9 @@ class KubeclientTest < MiniTest::Test
229
217
  end
230
218
 
231
219
  def test_entity_list_raw
232
- stub_request(:get, %r{/api/v1$})
233
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
234
- stub_request(:get, %r{/services})
235
- .to_return(body: open_test_file('entity_list.json'), status: 200)
220
+ stub_core_api_list
221
+ stub_get_services
236
222
 
237
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
238
223
  response = client.get_services(as: :raw)
239
224
 
240
225
  refute_empty(response)
@@ -243,14 +228,37 @@ class KubeclientTest < MiniTest::Test
243
228
  assert_requested(:get, 'http://localhost:8080/api/v1/services', times: 1)
244
229
  end
245
230
 
231
+ def test_entity_list_parsed
232
+ stub_core_api_list
233
+ stub_get_services
234
+
235
+ response = client.get_services(as: :parsed)
236
+ assert_equal Hash, response.class
237
+ assert_equal %w[metadata spec status], response['items'].first.keys
238
+ end
239
+
240
+ def test_entity_list_parsed_symbolized
241
+ stub_core_api_list
242
+ stub_get_services
243
+
244
+ response = client.get_services(as: :parsed_symbolized)
245
+ assert_equal Hash, response.class
246
+ assert_equal %i[metadata spec status], response[:items].first.keys
247
+ end
248
+
249
+ def test_entity_list_unknown
250
+ stub_core_api_list
251
+ stub_get_services
252
+
253
+ e = assert_raises(ArgumentError) { client.get_services(as: :whoops) }
254
+ assert_equal 'Unsupported format :whoops', e.message
255
+ end
256
+
246
257
  def test_entity_list_raw_failure
247
- stub_request(:get, %r{/api/v1$})
248
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
258
+ stub_core_api_list
249
259
  stub_request(:get, %r{/services})
250
260
  .to_return(body: open_test_file('entity_list.json'), status: 500)
251
261
 
252
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
253
-
254
262
  exception = assert_raises(Kubeclient::HttpError) { client.get_services(as: :raw) }
255
263
  assert_equal('500 Internal Server Error', exception.message)
256
264
  assert_equal(500, exception.error_code)
@@ -259,12 +267,9 @@ class KubeclientTest < MiniTest::Test
259
267
  def test_entities_with_label_selector
260
268
  selector = 'component=apiserver'
261
269
 
262
- stub_request(:get, %r{/api/v1$})
263
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
264
- stub_request(:get, %r{/services})
265
- .to_return(body: open_test_file('entity_list.json'), status: 200)
270
+ stub_core_api_list
271
+ stub_get_services
266
272
 
267
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
268
273
  services = client.get_services(label_selector: selector)
269
274
 
270
275
  assert_instance_of(Kubeclient::Common::EntityList, services)
@@ -278,12 +283,9 @@ class KubeclientTest < MiniTest::Test
278
283
  def test_entities_with_field_selector
279
284
  selector = 'involvedObject.name=redis-master'
280
285
 
281
- stub_request(:get, %r{/api/v1$})
282
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
283
- stub_request(:get, %r{/services})
284
- .to_return(body: open_test_file('entity_list.json'), status: 200)
286
+ stub_core_api_list
287
+ stub_get_services
285
288
 
286
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
287
289
  services = client.get_services(field_selector: selector)
288
290
 
289
291
  assert_instance_of(Kubeclient::Common::EntityList, services)
@@ -295,20 +297,17 @@ class KubeclientTest < MiniTest::Test
295
297
  end
296
298
 
297
299
  def test_empty_list
298
- stub_request(:get, %r{/api/v1$})
299
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
300
+ stub_core_api_list
300
301
  stub_request(:get, %r{/pods})
301
302
  .to_return(body: open_test_file('empty_pod_list.json'), status: 200)
302
303
 
303
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
304
304
  pods = client.get_pods
305
305
  assert_instance_of(Kubeclient::Common::EntityList, pods)
306
306
  assert_equal(0, pods.size)
307
307
  end
308
308
 
309
309
  def test_get_all
310
- stub_request(:get, %r{/api/v1$})
311
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
310
+ stub_core_api_list
312
311
 
313
312
  stub_request(:get, %r{/bindings})
314
313
  .to_return(body: open_test_file('bindings_list.json'), status: 404)
@@ -361,7 +360,6 @@ class KubeclientTest < MiniTest::Test
361
360
  stub_request(:get, %r{/serviceaccounts})
362
361
  .to_return(body: open_test_file('service_account_list.json'), status: 200)
363
362
 
364
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
365
363
  result = client.all_entities
366
364
  assert_equal(16, result.keys.size)
367
365
  assert_instance_of(Kubeclient::Common::EntityList, result['node'])
@@ -386,8 +384,7 @@ class KubeclientTest < MiniTest::Test
386
384
  end
387
385
 
388
386
  def test_get_all_raw
389
- stub_request(:get, %r{/api/v1$})
390
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
387
+ stub_core_api_list
391
388
 
392
389
  stub_request(:get, %r{/bindings})
393
390
  .to_return(body: open_test_file('bindings_list.json'), status: 404)
@@ -440,7 +437,6 @@ class KubeclientTest < MiniTest::Test
440
437
  stub_request(:get, %r{/serviceaccounts})
441
438
  .to_return(body: open_test_file('service_account_list.json'), status: 200)
442
439
 
443
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
444
440
  result = client.all_entities(as: :raw)
445
441
  assert_equal(16, result.keys.size)
446
442
 
@@ -655,13 +651,13 @@ class KubeclientTest < MiniTest::Test
655
651
  assert_equal(expected_msg, exception.message)
656
652
  end
657
653
 
658
- def test_init_user_and_bearer_token
654
+ def test_init_username_and_bearer_token_file
659
655
  expected_msg = 'Invalid auth options: specify only one of username/password,' \
660
656
  ' bearer_token or bearer_token_file'
661
657
  exception = assert_raises(ArgumentError) do
662
658
  Kubeclient::Client.new(
663
659
  'http://localhost:8080',
664
- auth_options: { username: 'username', bearer_token: 'token' }
660
+ auth_options: { username: 'username', bearer_token_file: 'token-file' }
665
661
  )
666
662
  end
667
663
  assert_equal(expected_msg, exception.message)
@@ -692,8 +688,7 @@ class KubeclientTest < MiniTest::Test
692
688
  end
693
689
 
694
690
  def test_api_bearer_token_file_success
695
- stub_request(:get, %r{/api/v1$})
696
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
691
+ stub_core_api_list
697
692
  stub_request(:get, 'http://localhost:8080/api/v1/pods')
698
693
  .with(headers: { Authorization: 'Bearer valid_token' })
699
694
  .to_return(body: open_test_file('pod_list.json'), status: 200)
@@ -711,8 +706,7 @@ class KubeclientTest < MiniTest::Test
711
706
  end
712
707
 
713
708
  def test_proxy_url
714
- stub_request(:get, %r{/api/v1$})
715
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
709
+ stub_core_api_list
716
710
 
717
711
  client = Kubeclient::Client.new('http://host:8080', 'v1')
718
712
  assert_equal(
@@ -772,12 +766,10 @@ class KubeclientTest < MiniTest::Test
772
766
 
773
767
  def test_nil_items
774
768
  # handle https://github.com/kubernetes/kubernetes/issues/13096
775
- stub_request(:get, %r{/api/v1$})
776
- .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
769
+ stub_core_api_list
777
770
  stub_request(:get, %r{/persistentvolumeclaims})
778
771
  .to_return(body: open_test_file('persistent_volume_claims_nil_items.json'), status: 200)
779
772
 
780
- client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
781
773
  client.get_persistent_volume_claims
782
774
  end
783
775
 
@@ -842,6 +834,20 @@ class KubeclientTest < MiniTest::Test
842
834
 
843
835
  private
844
836
 
837
+ def stub_get_services
838
+ stub_request(:get, %r{/services})
839
+ .to_return(body: open_test_file('entity_list.json'), status: 200)
840
+ end
841
+
842
+ def stub_core_api_list
843
+ stub_request(:get, %r{/api/v1$})
844
+ .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
845
+ end
846
+
847
+ def client
848
+ @client ||= Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
849
+ end
850
+
845
851
  # dup method creates a shallow copy which is not good in this case
846
852
  # since rename_keys changes the input hash
847
853
  # hence need to create a deep_copy
@@ -32,6 +32,43 @@ class TestPodLog < MiniTest::Test
32
32
  times: 1)
33
33
  end
34
34
 
35
+ def test_get_pod_log_since_time
36
+ stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log})
37
+ .to_return(body: open_test_file('pod_log.txt'),
38
+ status: 200)
39
+
40
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
41
+ retrieved_log = client.get_pod_log('redis-master-pod',
42
+ 'default',
43
+ timestamps: true,
44
+ since_time: '2018-04-27T18:30:17.480321984Z')
45
+
46
+ assert_equal(open_test_file('pod_log.txt').read, retrieved_log)
47
+
48
+ assert_requested(:get,
49
+ 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log?sinceTime=2018-04-27T18:30:17.480321984Z&timestamps=true',
50
+ times: 1)
51
+ end
52
+
53
+ def test_get_pod_log_tail_lines
54
+ selected_lines = open_test_file('pod_log.txt').to_a[-2..1].join
55
+
56
+ stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log})
57
+ .to_return(body: selected_lines,
58
+ status: 200)
59
+
60
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
61
+ retrieved_log = client.get_pod_log('redis-master-pod',
62
+ 'default',
63
+ tail_lines: 2)
64
+
65
+ assert_equal(selected_lines, retrieved_log)
66
+
67
+ assert_requested(:get,
68
+ 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log?tailLines=2',
69
+ times: 1)
70
+ end
71
+
35
72
  def test_watch_pod_log
36
73
  expected_lines = open_test_file('pod_log.txt').read.split("\n")
37
74
 
@@ -18,7 +18,7 @@ class TestWatch < MiniTest::Test
18
18
  client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
19
19
 
20
20
  client.watch_pods.to_enum.with_index do |notice, index|
21
- assert_instance_of(Kubeclient::Common::WatchNotice, notice)
21
+ assert_instance_of(Kubeclient::Resource, notice)
22
22
  assert_equal(expected[index]['type'], notice.type)
23
23
  assert_equal('Pod', notice.object.kind)
24
24
  assert_equal('php', notice.object.metadata.name)
@@ -62,24 +62,13 @@ class TestWatch < MiniTest::Test
62
62
  .to_return(body: open_test_file('pod_log.txt'),
63
63
  status: 200)
64
64
 
65
- stream = Kubeclient::Common::WatchStream.new(URI.parse(url), {}, as: :raw)
65
+ stream = Kubeclient::Common::WatchStream.new(URI.parse(url), {}, formatter: ->(v) { v })
66
66
  stream.to_enum.with_index do |line, index|
67
67
  assert_instance_of(String, line)
68
68
  assert_equal(expected_lines[index], line)
69
69
  end
70
70
  end
71
71
 
72
- # Ensure that WatchStream respects a format that's not JSON
73
- def test_watch_stream_unknown
74
- url = 'http://www.example.com/foobar'
75
- stub_request(:get, url)
76
- .to_return(body: open_test_file('pod_log.txt'),
77
- status: 200)
78
-
79
- stream = Kubeclient::Common::WatchStream.new(URI.parse(url), {}, as: :foo)
80
- assert_raises(NotImplementedError) { stream.each {} }
81
- end
82
-
83
72
  def test_watch_with_resource_version
84
73
  api_host = 'http://localhost:8080/api'
85
74
  version = '1995'
@@ -143,10 +132,10 @@ class TestWatch < MiniTest::Test
143
132
  client = Kubeclient::Client.new(api_host, 'v1')
144
133
  watcher = client.watch_events
145
134
 
146
- # explodes when Errno::EBADF is not caught
135
+ # explodes when StandardError is not caught
147
136
  watcher.each do
148
137
  watcher.finish
149
- raise Errno::EBADF
138
+ raise StandardError
150
139
  end
151
140
 
152
141
  assert_requested(:get, "#{api_host}/v1/watch/events", times: 1)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kubeclient
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alissa Bonas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-04 00:00:00.000000000 Z
11
+ date: 2018-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - '='
109
109
  - !ruby/object:Gem::Version
110
110
  version: 0.49.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: googleauth
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.5.1
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.5.1
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: rest-client
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -127,6 +141,9 @@ dependencies:
127
141
  requirement: !ruby/object:Gem::Requirement
128
142
  requirements:
129
143
  - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '1.0'
146
+ - - ">="
130
147
  - !ruby/object:Gem::Version
131
148
  version: 1.0.4
132
149
  type: :runtime
@@ -134,6 +151,9 @@ dependencies:
134
151
  version_requirements: !ruby/object:Gem::Requirement
135
152
  requirements:
136
153
  - - "~>"
154
+ - !ruby/object:Gem::Version
155
+ version: '1.0'
156
+ - - ">="
137
157
  - !ruby/object:Gem::Version
138
158
  version: 1.0.4
139
159
  - !ruby/object:Gem::Dependency
@@ -170,12 +190,12 @@ files:
170
190
  - lib/kubeclient/common.rb
171
191
  - lib/kubeclient/config.rb
172
192
  - lib/kubeclient/entity_list.rb
193
+ - lib/kubeclient/google_application_default_credentials.rb
173
194
  - lib/kubeclient/http_error.rb
174
195
  - lib/kubeclient/missing_kind_compatibility.rb
175
196
  - lib/kubeclient/resource.rb
176
197
  - lib/kubeclient/resource_not_found_error.rb
177
198
  - lib/kubeclient/version.rb
178
- - lib/kubeclient/watch_notice.rb
179
199
  - lib/kubeclient/watch_stream.rb
180
200
  - test/cassettes/kubernetes_guestbook.yml
181
201
  - test/config/allinone.kubeconfig
@@ -235,6 +255,7 @@ files:
235
255
  - test/test_component_status.rb
236
256
  - test/test_config.rb
237
257
  - test/test_endpoint.rb
258
+ - test/test_google_application_default_credentials.rb
238
259
  - test/test_guestbook_go.rb
239
260
  - test/test_helper.rb
240
261
  - test/test_kubeclient.rb
@@ -254,7 +275,6 @@ files:
254
275
  - test/test_service.rb
255
276
  - test/test_service_account.rb
256
277
  - test/test_watch.rb
257
- - test/test_watch_notice.rb
258
278
  - test/txt/pod_log.txt
259
279
  - test/valid_token_file
260
280
  homepage: https://github.com/abonas/kubeclient
@@ -277,7 +297,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
277
297
  version: '0'
278
298
  requirements: []
279
299
  rubyforge_project:
280
- rubygems_version: 2.5.2
300
+ rubygems_version: 2.6.13
281
301
  signing_key:
282
302
  specification_version: 4
283
303
  summary: A client for Kubernetes REST api
@@ -340,6 +360,7 @@ test_files:
340
360
  - test/test_component_status.rb
341
361
  - test/test_config.rb
342
362
  - test/test_endpoint.rb
363
+ - test/test_google_application_default_credentials.rb
343
364
  - test/test_guestbook_go.rb
344
365
  - test/test_helper.rb
345
366
  - test/test_kubeclient.rb
@@ -359,6 +380,5 @@ test_files:
359
380
  - test/test_service.rb
360
381
  - test/test_service_account.rb
361
382
  - test/test_watch.rb
362
- - test/test_watch_notice.rb
363
383
  - test/txt/pod_log.txt
364
384
  - test/valid_token_file
@@ -1,12 +0,0 @@
1
- require 'recursive_open_struct'
2
- module Kubeclient
3
- module Common
4
- # Represents an individual notice received from a Kubernetes watch
5
- class WatchNotice < RecursiveOpenStruct
6
- def initialize(hash = nil, args = {})
7
- args[:recurse_over_arrays] = true
8
- super(hash, args)
9
- end
10
- end
11
- end
12
- end
@@ -1,37 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class TestWatchNotice < MiniTest::Test
4
- #
5
- # Checks that elements of arrays are converted to instances of `RecursiveOpenStruct`, and that the
6
- # items can be accessed using the dot notation.
7
- #
8
- def test_recurse_over_arrays
9
- json = JSON.parse(open_test_file('node_notice.json').read)
10
- notice = Kubeclient::Common::WatchNotice.new(json)
11
- assert_kind_of(Array, notice.object.status.addresses)
12
- notice.object.status.addresses.each do |address|
13
- assert_kind_of(RecursiveOpenStruct, address)
14
- end
15
- assert_equal('InternalIP', notice.object.status.addresses[0].type)
16
- assert_equal('192.168.122.40', notice.object.status.addresses[0].address)
17
- assert_equal('Hostname', notice.object.status.addresses[1].type)
18
- assert_equal('openshift.local', notice.object.status.addresses[1].address)
19
- end
20
-
21
- #
22
- # Checks that even when arrays are converted to instances of `RecursiveOpenStruct` the items can
23
- # be accessed using the hash notation.
24
- #
25
- def test_access_array_items_as_hash
26
- json = JSON.parse(open_test_file('node_notice.json').read)
27
- notice = Kubeclient::Common::WatchNotice.new(json)
28
- assert_kind_of(Array, notice.object.status.addresses)
29
- notice.object.status.addresses.each do |address|
30
- assert_kind_of(RecursiveOpenStruct, address)
31
- end
32
- assert_equal('InternalIP', notice.object.status.addresses[0]['type'])
33
- assert_equal('192.168.122.40', notice.object.status.addresses[0]['address'])
34
- assert_equal('Hostname', notice.object.status.addresses[1]['type'])
35
- assert_equal('openshift.local', notice.object.status.addresses[1]['address'])
36
- end
37
- end