kubeclient 4.1.2 → 4.2.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/.rubocop.yml +2 -0
- data/CHANGELOG.md +11 -3
- data/README.md +11 -4
- data/RELEASING.md +3 -1
- data/lib/kubeclient.rb +1 -0
- data/lib/kubeclient/common.rb +2 -12
- data/lib/kubeclient/config.rb +36 -2
- data/lib/kubeclient/exec_credentials.rb +60 -0
- data/lib/kubeclient/version.rb +1 -1
- data/test/config/execauth.kubeconfig +62 -0
- data/test/test_common.rb +0 -5
- data/test/test_config.rb +69 -5
- data/test/test_exec_credentials.rb +125 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2bc02012cb0c78fc1ec3335e836c2749973e432022083fb3b95bed3d702332a5
|
4
|
+
data.tar.gz: 7b5d68aa1c1200d387a086a09f3a8ca628e892c84c590ef76180b37f60f8ca88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5c2c2d281b9ed728faf12b8a7937283225b509d6eb4ca4dc7c6245024e1677799ced3adc1a14bf111dab9092b9061af41b0b7924d54dbef5a9f72ff90d554e9
|
7
|
+
data.tar.gz: 7c55c0f9c3595045ecb98b1c35d682d8aa8bb3907c3a208c33a32980890e702fca58faa927d0c82b59a69e27e5508cf1efce119ea76846c4f7b5c4bd4ee85944
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -4,14 +4,22 @@ 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
5
|
Kubeclient release versioning follows [SemVer](https://semver.org/).
|
6
6
|
|
7
|
-
## 4.
|
7
|
+
## 4.2.0 — 2018-12-20
|
8
8
|
|
9
|
-
###
|
10
|
-
-
|
9
|
+
### Added
|
10
|
+
- Support `user: exec: ...` credential plugins like in Go client (#363, #375).
|
11
|
+
|
12
|
+
### Security
|
13
|
+
- Really made `Kubeclient::Config.new(data, nil)` prevent external file lookups. (#372)
|
14
|
+
README documented this since 3.1.1 (#334) but alas that was a lie — absolute paths always worked.
|
15
|
+
Now this also prevents credential plugin execution.
|
16
|
+
|
17
|
+
Even in this mode, using config from untrusted sources is not recommended.
|
11
18
|
|
12
19
|
## 4.1.1 — 2018-12-17
|
13
20
|
|
14
21
|
### Fixed
|
22
|
+
|
15
23
|
- Fixed method names for non-suffix plurals such as y -> ies (#377).
|
16
24
|
|
17
25
|
## 4.1.0 — 2018-11-28 — REGRESSION
|
data/README.md
CHANGED
@@ -268,6 +268,11 @@ If you've been using `kubectl` and have a `.kube/config` file (possibly referenc
|
|
268
268
|
config = Kubeclient::Config.read(ENV['KUBECONFIG'] || '/path/to/.kube/config')
|
269
269
|
```
|
270
270
|
|
271
|
+
This will lookup external files; relative paths will be resolved relative to the file's directory, if config refers to them with relative path.
|
272
|
+
This includes external [`exec:` credential plugins][exec] to be executed.
|
273
|
+
|
274
|
+
[exec]: https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins
|
275
|
+
|
271
276
|
You can also construct `Config` directly from nested data. For example if you have JSON or YAML config data in a variable:
|
272
277
|
|
273
278
|
```ruby
|
@@ -277,7 +282,7 @@ config = Kubeclient::Config.new(JSON.parse(json_text), nil)
|
|
277
282
|
```
|
278
283
|
|
279
284
|
The 2nd argument is a base directory for finding external files, if config refers to them with relative path.
|
280
|
-
Setting it to `nil` disables file lookups. (A config can be self-contained by using inline fields such as `client-certificate-data`.)
|
285
|
+
Setting it to `nil` disables file lookups, and `exec:` execution - such configs will raise an exception. (A config can be self-contained by using inline fields such as `client-certificate-data`.)
|
281
286
|
|
282
287
|
To create a client based on a Config object:
|
283
288
|
|
@@ -297,7 +302,9 @@ Kubeclient::Client.new(
|
|
297
302
|
|
298
303
|
#### Security: Don't use config from untrusted sources
|
299
304
|
|
300
|
-
|
305
|
+
`Config.read` is catastrophically unsafe — it will execute arbitrary command lines specified by the config!
|
306
|
+
|
307
|
+
`Config.new(data, nil)` is better but Kubeclient was never reviewed for behaving safely with malicious / malformed config.
|
301
308
|
It might crash / misbehave in unexpected ways...
|
302
309
|
|
303
310
|
#### namespace
|
@@ -604,9 +611,9 @@ Checking the type of a resource can be done using:
|
|
604
611
|
|
605
612
|
update_* delete_* and patch_* now return a RecursiveOpenStruct like the get_* methods
|
606
613
|
|
607
|
-
The
|
614
|
+
The `Kubeclient::Client` class raises `Kubeclient::HttpError` or subclasses now. Catching `KubeException` still works but is deprecated.
|
608
615
|
|
609
|
-
`Kubeclient::Config#context` raises KeyError instead of RuntimeError for non-existent context name.
|
616
|
+
`Kubeclient::Config#context` raises `KeyError` instead of `RuntimeError` for non-existent context name.
|
610
617
|
|
611
618
|
<a name="past_version_1.2.0">
|
612
619
|
|
data/RELEASING.md
CHANGED
@@ -55,7 +55,9 @@ bundle exec rake test rubocop
|
|
55
55
|
|
56
56
|
Create and push the tag:
|
57
57
|
```bash
|
58
|
-
gem tag --
|
58
|
+
gem tag --no-push
|
59
|
+
git push --tags --dry-run https://github.com/abonas/kubeclient # Check for unexpected tags
|
60
|
+
git push --tags https://github.com/abonas/kubeclient
|
59
61
|
```
|
60
62
|
|
61
63
|
Release onto rubygems.org:
|
data/lib/kubeclient.rb
CHANGED
@@ -5,6 +5,7 @@ require 'kubeclient/common'
|
|
5
5
|
require 'kubeclient/config'
|
6
6
|
require 'kubeclient/entity_list'
|
7
7
|
require 'kubeclient/google_application_default_credentials'
|
8
|
+
require 'kubeclient/exec_credentials'
|
8
9
|
require 'kubeclient/http_error'
|
9
10
|
require 'kubeclient/missing_kind_compatibility'
|
10
11
|
require 'kubeclient/resource'
|
data/lib/kubeclient/common.rb
CHANGED
@@ -163,7 +163,8 @@ module Kubeclient
|
|
163
163
|
method_names = [prefix_underscores + singular_suffix, # "network_policy"
|
164
164
|
prefix_underscores + plural_suffix] # "network_policies"
|
165
165
|
else
|
166
|
-
|
166
|
+
# Something weird, can't infer underscores for plural so just give them up
|
167
|
+
method_names = [singular_name, name]
|
167
168
|
end
|
168
169
|
end
|
169
170
|
end
|
@@ -175,17 +176,6 @@ module Kubeclient
|
|
175
176
|
)
|
176
177
|
end
|
177
178
|
|
178
|
-
def self.resolve_unconventional_method_names(name, kind, singular_name)
|
179
|
-
underscored_name = name.tr('-', '_')
|
180
|
-
singular_underscores = ClientMixin.underscore_entity(kind)
|
181
|
-
if underscored_name.start_with?(singular_underscores)
|
182
|
-
[singular_underscores, underscored_name]
|
183
|
-
else
|
184
|
-
# fallback to lowercase, no separators for both names
|
185
|
-
[singular_name, underscored_name.tr('_', '')]
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
179
|
def handle_uri(uri, path)
|
190
180
|
raise ArgumentError, 'Missing uri' unless uri
|
191
181
|
@api_endpoint = (uri.is_a?(URI) ? uri : URI.parse(uri))
|
data/lib/kubeclient/config.rb
CHANGED
@@ -18,12 +18,17 @@ module Kubeclient
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
# data (Hash) - Parsed kubeconfig data.
|
22
|
+
# kcfg_path (string) - Base directory for resolving relative references to external files.
|
23
|
+
# If set to nil, all external lookups & commands are disabled (even for absolute paths).
|
24
|
+
# See also the more convenient Config.read
|
25
|
+
def initialize(data, kcfg_path)
|
26
|
+
@kcfg = data
|
23
27
|
@kcfg_path = kcfg_path
|
24
28
|
raise 'Unknown kubeconfig version' if @kcfg['apiVersion'] != 'v1'
|
25
29
|
end
|
26
30
|
|
31
|
+
# Builds Config instance by parsing given file, with lookups relative to file's directory.
|
27
32
|
def self.read(filename)
|
28
33
|
parsed = YAML.safe_load(File.read(filename), [Date, Time])
|
29
34
|
Config.new(parsed, File.dirname(filename))
|
@@ -65,10 +70,35 @@ module Kubeclient
|
|
65
70
|
|
66
71
|
private
|
67
72
|
|
73
|
+
def allow_external_lookups?
|
74
|
+
@kcfg_path != nil
|
75
|
+
end
|
76
|
+
|
68
77
|
def ext_file_path(path)
|
78
|
+
unless allow_external_lookups?
|
79
|
+
raise "Kubeclient::Config: external lookups disabled, can't load '#{path}'"
|
80
|
+
end
|
69
81
|
Pathname(path).absolute? ? path : File.join(@kcfg_path, path)
|
70
82
|
end
|
71
83
|
|
84
|
+
def ext_command_path(path)
|
85
|
+
unless allow_external_lookups?
|
86
|
+
raise "Kubeclient::Config: external lookups disabled, can't execute '#{path}'"
|
87
|
+
end
|
88
|
+
# Like go client https://github.com/kubernetes/kubernetes/pull/59495#discussion_r171138995,
|
89
|
+
# distinguish 3 cases:
|
90
|
+
# - absolute (e.g. /path/to/foo)
|
91
|
+
# - $PATH-based (e.g. curl)
|
92
|
+
# - relative to config file's dir (e.g. ./foo)
|
93
|
+
if Pathname(path).absolute?
|
94
|
+
path
|
95
|
+
elsif File.basename(path) == path
|
96
|
+
path
|
97
|
+
else
|
98
|
+
File.join(@kcfg_path, path)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
72
102
|
def fetch_context(context_name)
|
73
103
|
context = @kcfg['contexts'].detect do |x|
|
74
104
|
break x['context'] if x['name'] == context_name
|
@@ -119,6 +149,10 @@ module Kubeclient
|
|
119
149
|
options = {}
|
120
150
|
if user.key?('token')
|
121
151
|
options[:bearer_token] = user['token']
|
152
|
+
elsif user.key?('exec')
|
153
|
+
exec_opts = user['exec'].dup
|
154
|
+
exec_opts['command'] = ext_command_path(exec_opts['command']) if exec_opts['command']
|
155
|
+
options[:bearer_token] = Kubeclient::ExecCredentials.token(exec_opts)
|
122
156
|
else
|
123
157
|
%w[username password].each do |attr|
|
124
158
|
options[attr.to_sym] = user[attr] if user.key?(attr)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kubeclient
|
4
|
+
# An exec-based client auth provide
|
5
|
+
# https://kubernetes.io/docs/reference/access-authn-authz/authentication/#configuration
|
6
|
+
# Inspired by https://github.com/kubernetes/client-go/blob/master/plugin/pkg/client/auth/exec/exec.go
|
7
|
+
class ExecCredentials
|
8
|
+
class << self
|
9
|
+
def token(opts)
|
10
|
+
require 'open3'
|
11
|
+
require 'json'
|
12
|
+
|
13
|
+
raise ArgumentError, 'exec options are required' if opts.nil?
|
14
|
+
|
15
|
+
cmd = opts['command']
|
16
|
+
args = opts['args']
|
17
|
+
env = map_env(opts['env'])
|
18
|
+
|
19
|
+
# Validate exec options
|
20
|
+
validate_opts(opts)
|
21
|
+
|
22
|
+
out, err, st = Open3.capture3(env, cmd, *args)
|
23
|
+
|
24
|
+
raise "exec command failed: #{err}" unless st.success?
|
25
|
+
|
26
|
+
creds = JSON.parse(out)
|
27
|
+
validate_credentials(opts, creds)
|
28
|
+
creds['status']['token']
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def validate_opts(opts)
|
34
|
+
raise KeyError, 'exec command is required' unless opts['command']
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_credentials(opts, creds)
|
38
|
+
# out should have ExecCredential structure
|
39
|
+
raise 'invalid credentials' if creds.nil?
|
40
|
+
|
41
|
+
# Verify apiVersion?
|
42
|
+
api_version = opts['apiVersion']
|
43
|
+
if api_version && api_version != creds['apiVersion']
|
44
|
+
raise "exec plugin is configured to use API version #{api_version}, " \
|
45
|
+
"plugin returned version #{creds['apiVersion']}"
|
46
|
+
end
|
47
|
+
|
48
|
+
raise 'exec plugin didn\'t return a status field' if creds['status'].nil?
|
49
|
+
raise 'exec plugin didn\'t return a token' if creds['status']['token'].nil?
|
50
|
+
end
|
51
|
+
|
52
|
+
# Transform name/value pairs to hash
|
53
|
+
def map_env(env)
|
54
|
+
return {} unless env
|
55
|
+
|
56
|
+
Hash[env.map { |e| [e['name'], e['value']] }]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/kubeclient/version.rb
CHANGED
@@ -0,0 +1,62 @@
|
|
1
|
+
apiVersion: v1
|
2
|
+
clusters:
|
3
|
+
- cluster:
|
4
|
+
server: https://localhost:8443
|
5
|
+
insecure-skip-tls-verify: true
|
6
|
+
name: localhost:8443
|
7
|
+
contexts:
|
8
|
+
- context:
|
9
|
+
cluster: localhost:8443
|
10
|
+
namespace: default
|
11
|
+
user: system:admin:exec-search-path
|
12
|
+
name: localhost/system:admin:exec-search-path
|
13
|
+
- context:
|
14
|
+
cluster: localhost:8443
|
15
|
+
namespace: default
|
16
|
+
user: system:admin:exec-relative-path
|
17
|
+
name: localhost/system:admin:exec-relative-path
|
18
|
+
- context:
|
19
|
+
cluster: localhost:8443
|
20
|
+
namespace: default
|
21
|
+
user: system:admin:exec-absolute-path
|
22
|
+
name: localhost/system:admin:exec-absolute-path
|
23
|
+
kind: Config
|
24
|
+
preferences: {}
|
25
|
+
users:
|
26
|
+
- name: system:admin:exec-search-path
|
27
|
+
user:
|
28
|
+
exec:
|
29
|
+
# Command to execute. Required.
|
30
|
+
command: "example-exec-plugin"
|
31
|
+
|
32
|
+
# API version to use when decoding the ExecCredentials resource. Required.
|
33
|
+
#
|
34
|
+
# The API version returned by the plugin MUST match the version listed here.
|
35
|
+
#
|
36
|
+
# To integrate with tools that support multiple versions (such as client.authentication.k8s.io/v1alpha1),
|
37
|
+
# set an environment variable or pass an argument to the tool that indicates which version the exec plugin expects.
|
38
|
+
apiVersion: "client.authentication.k8s.io/v1beta1"
|
39
|
+
|
40
|
+
# Environment variables to set when executing the plugin. Optional.
|
41
|
+
env:
|
42
|
+
- name: "FOO"
|
43
|
+
value: "bar"
|
44
|
+
|
45
|
+
# Arguments to pass when executing the plugin. Optional.
|
46
|
+
args:
|
47
|
+
- "arg1"
|
48
|
+
- "arg2"
|
49
|
+
|
50
|
+
- name: system:admin:exec-relative-path
|
51
|
+
user:
|
52
|
+
exec:
|
53
|
+
# Command to execute. Required.
|
54
|
+
command: "dir/example-exec-plugin"
|
55
|
+
apiVersion: "client.authentication.k8s.io/v1beta1"
|
56
|
+
|
57
|
+
- name: system:admin:exec-absolute-path
|
58
|
+
user:
|
59
|
+
exec:
|
60
|
+
# Command to execute. Required.
|
61
|
+
command: "/abs/path/example-exec-plugin"
|
62
|
+
apiVersion: "client.authentication.k8s.io/v1beta1"
|
data/test/test_common.rb
CHANGED
@@ -81,11 +81,6 @@ class CommonTest < MiniTest::Test
|
|
81
81
|
LatinDatum latindata latin_datum latin_data
|
82
82
|
Noseparator noseparators noseparator noseparators
|
83
83
|
lowercase lowercases lowercase lowercases
|
84
|
-
TestWithDash test-with-dashes test_with_dash test_with_dashes
|
85
|
-
TestUnderscore test_underscores test_underscore test_underscores
|
86
|
-
TestMismatch other-odd-name testmismatch otheroddname
|
87
|
-
MixedDashMinus mixed-dash_minuses mixed_dash_minus mixed_dash_minuses
|
88
|
-
SameUptoWordboundary sameup-toword-boundarys sameuptowordboundary sameuptowordboundarys
|
89
84
|
].each_slice(4) do |kind, plural, expected_single, expected_plural|
|
90
85
|
method_names = Kubeclient::ClientMixin.parse_definition(kind, plural).method_names
|
91
86
|
assert_equal(method_names[0], expected_single)
|
data/test/test_config.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative 'test_helper'
|
2
2
|
require 'yaml'
|
3
|
+
require 'open3'
|
3
4
|
|
4
5
|
# Testing Kubernetes client configuration
|
5
6
|
class KubeclientConfigTest < MiniTest::Test
|
@@ -28,18 +29,18 @@ class KubeclientConfigTest < MiniTest::Test
|
|
28
29
|
# kcfg_path = nil should prevent file access
|
29
30
|
config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
|
30
31
|
assert_raises(StandardError) do
|
31
|
-
config.context
|
32
|
+
config.context
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
35
36
|
def test_external_nopath_absolute
|
36
37
|
yaml = File.read(config_file('external.kubeconfig'))
|
37
38
|
# kcfg_path = nil should prevent file access, even if absolute path specified
|
38
|
-
ca_absolute_path = File.absolute_path(config_file('external
|
39
|
-
yaml = yaml.gsub('external-
|
39
|
+
ca_absolute_path = File.absolute_path(config_file('external-'))
|
40
|
+
yaml = yaml.gsub('external-', ca_absolute_path)
|
40
41
|
config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
|
41
42
|
assert_raises(StandardError) do
|
42
|
-
config.context
|
43
|
+
config.context
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
@@ -73,6 +74,55 @@ class KubeclientConfigTest < MiniTest::Test
|
|
73
74
|
Kubeclient::Config.read(config_file('timestamps.kubeconfig'))
|
74
75
|
end
|
75
76
|
|
77
|
+
def test_user_exec
|
78
|
+
token = '0123456789ABCDEF0123456789ABCDEF'
|
79
|
+
creds = {
|
80
|
+
'apiVersion': 'client.authentication.k8s.io/v1beta1',
|
81
|
+
'status': {
|
82
|
+
'token': token
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
config = Kubeclient::Config.read(config_file('execauth.kubeconfig'))
|
87
|
+
assert_equal(['localhost/system:admin:exec-search-path',
|
88
|
+
'localhost/system:admin:exec-relative-path',
|
89
|
+
'localhost/system:admin:exec-absolute-path'],
|
90
|
+
config.contexts)
|
91
|
+
|
92
|
+
# A bare command name in config means search PATH, so it's executed as bare command.
|
93
|
+
stub_exec(%r{^example-exec-plugin$}, creds) do
|
94
|
+
context = config.context('localhost/system:admin:exec-search-path')
|
95
|
+
check_context(context, ssl: false)
|
96
|
+
assert_equal(token, context.auth_options[:bearer_token])
|
97
|
+
end
|
98
|
+
|
99
|
+
# A relative path is taken relative to the dir of the kubeconfig.
|
100
|
+
stub_exec(%r{.*config/dir/example-exec-plugin$}, creds) do
|
101
|
+
context = config.context('localhost/system:admin:exec-relative-path')
|
102
|
+
check_context(context, ssl: false)
|
103
|
+
assert_equal(token, context.auth_options[:bearer_token])
|
104
|
+
end
|
105
|
+
|
106
|
+
# An absolute path is taken as-is.
|
107
|
+
stub_exec(%r{^/abs/path/example-exec-plugin$}, creds) do
|
108
|
+
context = config.context('localhost/system:admin:exec-absolute-path')
|
109
|
+
check_context(context, ssl: false)
|
110
|
+
assert_equal(token, context.auth_options[:bearer_token])
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_user_exec_nopath
|
115
|
+
yaml = File.read(config_file('execauth.kubeconfig'))
|
116
|
+
config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
|
117
|
+
config.contexts.each do |context_name|
|
118
|
+
Open3.stub(:capture3, proc { flunk 'should not execute command' }) do
|
119
|
+
assert_raises(StandardError) do
|
120
|
+
config.context(context_name)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
76
126
|
private
|
77
127
|
|
78
128
|
def check_context(context, ssl: true)
|
@@ -102,6 +152,20 @@ class KubeclientConfigTest < MiniTest::Test
|
|
102
152
|
end
|
103
153
|
|
104
154
|
def config_file(name)
|
105
|
-
File.
|
155
|
+
File.join(File.dirname(__FILE__), 'config', name)
|
156
|
+
end
|
157
|
+
|
158
|
+
def stub_exec(command_regexp, creds)
|
159
|
+
st = Minitest::Mock.new
|
160
|
+
st.expect(:success?, true)
|
161
|
+
|
162
|
+
capture3_stub = lambda do |_env, command, *_args|
|
163
|
+
assert_match command_regexp, command
|
164
|
+
[JSON.dump(creds), nil, st]
|
165
|
+
end
|
166
|
+
|
167
|
+
Open3.stub(:capture3, capture3_stub) do
|
168
|
+
yield
|
169
|
+
end
|
106
170
|
end
|
107
171
|
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require 'open3'
|
3
|
+
|
4
|
+
# Unit tests for the ExecCredentials token provider
|
5
|
+
class ExecCredentialsTest < MiniTest::Test
|
6
|
+
def test_exec_opts_missing
|
7
|
+
expected_msg =
|
8
|
+
'exec options are required'
|
9
|
+
exception = assert_raises(ArgumentError) do
|
10
|
+
Kubeclient::ExecCredentials.token(nil)
|
11
|
+
end
|
12
|
+
assert_equal(expected_msg, exception.message)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_exec_command_missing
|
16
|
+
expected_msg =
|
17
|
+
'exec command is required'
|
18
|
+
exception = assert_raises(KeyError) do
|
19
|
+
Kubeclient::ExecCredentials.token({})
|
20
|
+
end
|
21
|
+
assert_equal(expected_msg, exception.message)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_exec_command_failure
|
25
|
+
err = 'Error'
|
26
|
+
expected_msg =
|
27
|
+
"exec command failed: #{err}"
|
28
|
+
|
29
|
+
st = Minitest::Mock.new
|
30
|
+
st.expect(:success?, false)
|
31
|
+
|
32
|
+
opts = { 'command' => 'dummy' }
|
33
|
+
|
34
|
+
Open3.stub(:capture3, [nil, err, st]) do
|
35
|
+
exception = assert_raises(RuntimeError) do
|
36
|
+
Kubeclient::ExecCredentials.token(opts)
|
37
|
+
end
|
38
|
+
assert_equal(expected_msg, exception.message)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_token
|
43
|
+
opts = { 'command' => 'dummy' }
|
44
|
+
|
45
|
+
creds = JSON.dump(
|
46
|
+
'apiVersion': 'client.authentication.k8s.io/v1alpha1',
|
47
|
+
'status': {
|
48
|
+
'token': '0123456789ABCDEF0123456789ABCDEF'
|
49
|
+
}
|
50
|
+
)
|
51
|
+
|
52
|
+
st = Minitest::Mock.new
|
53
|
+
st.expect(:success?, true)
|
54
|
+
|
55
|
+
Open3.stub(:capture3, [creds, nil, st]) do
|
56
|
+
assert_equal('0123456789ABCDEF0123456789ABCDEF', Kubeclient::ExecCredentials.token(opts))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_status_missing
|
61
|
+
opts = { 'command' => 'dummy' }
|
62
|
+
|
63
|
+
creds = JSON.dump('apiVersion': 'client.authentication.k8s.io/v1alpha1')
|
64
|
+
|
65
|
+
st = Minitest::Mock.new
|
66
|
+
st.expect(:success?, true)
|
67
|
+
|
68
|
+
expected_msg = 'exec plugin didn\'t return a status field'
|
69
|
+
|
70
|
+
Open3.stub(:capture3, [creds, nil, st]) do
|
71
|
+
exception = assert_raises(RuntimeError) do
|
72
|
+
Kubeclient::ExecCredentials.token(opts)
|
73
|
+
end
|
74
|
+
assert_equal(expected_msg, exception.message)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_token_missing
|
79
|
+
opts = { 'command' => 'dummy' }
|
80
|
+
|
81
|
+
creds = JSON.dump(
|
82
|
+
'apiVersion': 'client.authentication.k8s.io/v1alpha1',
|
83
|
+
'status': {}
|
84
|
+
)
|
85
|
+
|
86
|
+
st = Minitest::Mock.new
|
87
|
+
st.expect(:success?, true)
|
88
|
+
|
89
|
+
expected_msg = 'exec plugin didn\'t return a token'
|
90
|
+
|
91
|
+
Open3.stub(:capture3, [creds, nil, st]) do
|
92
|
+
exception = assert_raises(RuntimeError) do
|
93
|
+
Kubeclient::ExecCredentials.token(opts)
|
94
|
+
end
|
95
|
+
assert_equal(expected_msg, exception.message)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_api_version_mismatch
|
100
|
+
api_version = 'client.authentication.k8s.io/v1alpha1'
|
101
|
+
expected_version = 'client.authentication.k8s.io/v1beta1'
|
102
|
+
|
103
|
+
opts = {
|
104
|
+
'command' => 'dummy',
|
105
|
+
'apiVersion' => expected_version
|
106
|
+
}
|
107
|
+
|
108
|
+
creds = JSON.dump(
|
109
|
+
'apiVersion': api_version
|
110
|
+
)
|
111
|
+
|
112
|
+
st = Minitest::Mock.new
|
113
|
+
st.expect(:success?, true)
|
114
|
+
|
115
|
+
expected_msg = "exec plugin is configured to use API version #{expected_version}," \
|
116
|
+
" plugin returned version #{api_version}"
|
117
|
+
|
118
|
+
Open3.stub(:capture3, [creds, nil, st]) do
|
119
|
+
exception = assert_raises(RuntimeError) do
|
120
|
+
Kubeclient::ExecCredentials.token(opts)
|
121
|
+
end
|
122
|
+
assert_equal(expected_msg, exception.message)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
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: 4.
|
4
|
+
version: 4.2.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-12-
|
11
|
+
date: 2018-12-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -191,6 +191,7 @@ files:
|
|
191
191
|
- lib/kubeclient/common.rb
|
192
192
|
- lib/kubeclient/config.rb
|
193
193
|
- lib/kubeclient/entity_list.rb
|
194
|
+
- lib/kubeclient/exec_credentials.rb
|
194
195
|
- lib/kubeclient/google_application_default_credentials.rb
|
195
196
|
- lib/kubeclient/http_error.rb
|
196
197
|
- lib/kubeclient/missing_kind_compatibility.rb
|
@@ -200,6 +201,7 @@ files:
|
|
200
201
|
- lib/kubeclient/watch_stream.rb
|
201
202
|
- test/cassettes/kubernetes_guestbook.yml
|
202
203
|
- test/config/allinone.kubeconfig
|
204
|
+
- test/config/execauth.kubeconfig
|
203
205
|
- test/config/external-ca.pem
|
204
206
|
- test/config/external-cert.pem
|
205
207
|
- test/config/external-key.rsa
|
@@ -268,6 +270,7 @@ files:
|
|
268
270
|
- test/test_component_status.rb
|
269
271
|
- test/test_config.rb
|
270
272
|
- test/test_endpoint.rb
|
273
|
+
- test/test_exec_credentials.rb
|
271
274
|
- test/test_google_application_default_credentials.rb
|
272
275
|
- test/test_guestbook_go.rb
|
273
276
|
- test/test_helper.rb
|
@@ -318,6 +321,7 @@ summary: A client for Kubernetes REST api
|
|
318
321
|
test_files:
|
319
322
|
- test/cassettes/kubernetes_guestbook.yml
|
320
323
|
- test/config/allinone.kubeconfig
|
324
|
+
- test/config/execauth.kubeconfig
|
321
325
|
- test/config/external-ca.pem
|
322
326
|
- test/config/external-cert.pem
|
323
327
|
- test/config/external-key.rsa
|
@@ -386,6 +390,7 @@ test_files:
|
|
386
390
|
- test/test_component_status.rb
|
387
391
|
- test/test_config.rb
|
388
392
|
- test/test_endpoint.rb
|
393
|
+
- test/test_exec_credentials.rb
|
389
394
|
- test/test_google_application_default_credentials.rb
|
390
395
|
- test/test_guestbook_go.rb
|
391
396
|
- test/test_helper.rb
|