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 +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +21 -3
- data/README.md +85 -10
- data/kubeclient.gemspec +3 -1
- data/lib/kubeclient.rb +1 -1
- data/lib/kubeclient/common.rb +60 -26
- data/lib/kubeclient/config.rb +8 -5
- data/lib/kubeclient/google_application_default_credentials.rb +16 -0
- data/lib/kubeclient/version.rb +1 -1
- data/lib/kubeclient/watch_stream.rb +4 -10
- data/test/test_common.rb +26 -0
- data/test/test_config.rb +1 -0
- data/test/test_google_application_default_credentials.rb +15 -0
- data/test/test_kubeclient.rb +61 -55
- data/test/test_pod_log.rb +37 -0
- data/test/test_watch.rb +4 -15
- metadata +26 -6
- data/lib/kubeclient/watch_notice.rb +0 -12
- data/test/test_watch_notice.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad5e0d0d632be2585068c14cf2eb218e20788c83
|
4
|
+
data.tar.gz: f7b002dcb8a7a49381b3bdbe8e6eaf2abdbe1f4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0bec0e053d54fa34c6b058c071b55e681d0c97497808ba7e23703dcfde1dff5e86be185a2b3cf0c1c834b50857b11298ff524f14ed42c2145d18d859b85924c5
|
7
|
+
data.tar.gz: 5f2d7cb7770b4e7d3414b468704db641929eafde9452c60a863ab7d542cb3ea9fc1e35f8d2cddb3f85ccf02eb8a1dd078503748822e2ba7db3b9383210788cfe
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -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.
|
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
|
-
|
138
|
-
|
139
|
-
[
|
140
|
-
|
141
|
-
a/ `/var/run/secrets/kubernetes.io/serviceaccount/token
|
142
|
-
|
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
|
-
|
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
|
-
|
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
|
data/kubeclient.gemspec
CHANGED
@@ -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
|
data/lib/kubeclient.rb
CHANGED
@@ -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
|
data/lib/kubeclient/common.rb
CHANGED
@@ -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(
|
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
|
-
|
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(
|
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(
|
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(
|
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(
|
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,
|
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),
|
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
|
-
|
436
|
-
|
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
|
-
|
439
|
-
|
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
|
data/lib/kubeclient/config.rb
CHANGED
@@ -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
|
-
[
|
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
|
data/lib/kubeclient/version.rb
CHANGED
@@ -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,
|
7
|
+
def initialize(uri, http_options, formatter:)
|
8
8
|
@uri = uri
|
9
9
|
@http_client = nil
|
10
10
|
@http_options = http_options
|
11
|
-
@
|
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
|
-
|
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
|
30
|
+
rescue StandardError
|
37
31
|
raise unless @finished
|
38
32
|
end
|
39
33
|
|
data/test/test_common.rb
CHANGED
@@ -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
|
data/test/test_config.rb
CHANGED
@@ -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
|
data/test/test_kubeclient.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
214
|
-
|
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
|
-
|
233
|
-
|
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
|
-
|
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
|
-
|
263
|
-
|
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
|
-
|
282
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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',
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/test/test_pod_log.rb
CHANGED
@@ -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×tamps=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
|
|
data/test/test_watch.rb
CHANGED
@@ -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::
|
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), {},
|
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
|
135
|
+
# explodes when StandardError is not caught
|
147
136
|
watcher.each do
|
148
137
|
watcher.finish
|
149
|
-
raise
|
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.
|
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-
|
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.
|
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
|
data/test/test_watch_notice.rb
DELETED
@@ -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
|