k8s-client 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/.rubocop.relaxed.yml +176 -0
- data/.rubocop.yml +57 -0
- data/Rakefile +11 -1
- data/bin/k8s-client +32 -36
- data/k8s-client.gemspec +2 -0
- data/lib/k8s-client.rb +2 -16
- data/lib/k8s/api.rb +3 -1
- data/lib/k8s/api/metav1.rb +2 -0
- data/lib/k8s/api/metav1/api_group.rb +2 -0
- data/lib/k8s/api/metav1/api_resource.rb +2 -0
- data/lib/k8s/api/metav1/list.rb +2 -0
- data/lib/k8s/api/metav1/object.rb +2 -0
- data/lib/k8s/api/metav1/status.rb +2 -0
- data/lib/k8s/api/version.rb +2 -0
- data/lib/k8s/api_client.rb +25 -28
- data/lib/k8s/client.rb +34 -15
- data/lib/k8s/client/version.rb +3 -1
- data/lib/k8s/config.rb +14 -7
- data/lib/k8s/error.rb +27 -26
- data/lib/k8s/logging.rb +4 -2
- data/lib/k8s/resource.rb +9 -7
- data/lib/k8s/resource_client.rb +39 -45
- data/lib/k8s/stack.rb +22 -14
- data/lib/k8s/transport.rb +59 -50
- data/lib/k8s/util.rb +10 -9
- metadata +32 -2
data/k8s-client.gemspec
CHANGED
@@ -28,9 +28,11 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_runtime_dependency "deep_merge", "~> 1.2.1"
|
29
29
|
spec.add_runtime_dependency "recursive-open-struct", "~> 1.1.0"
|
30
30
|
spec.add_runtime_dependency 'hashdiff', '~> 0.3.7'
|
31
|
+
spec.add_runtime_dependency 'jsonpath', '~> 0.9.5'
|
31
32
|
|
32
33
|
spec.add_development_dependency "bundler", "~> 1.16"
|
33
34
|
spec.add_development_dependency "rake", "~> 10.0"
|
34
35
|
spec.add_development_dependency "rspec", "~> 3.7"
|
35
36
|
spec.add_development_dependency "webmock", "~> 3.4.2"
|
37
|
+
spec.add_development_dependency "rubocop", "~> 0.59"
|
36
38
|
end
|
data/lib/k8s-client.rb
CHANGED
@@ -1,17 +1,3 @@
|
|
1
|
-
#
|
2
|
-
module K8s
|
3
|
-
require 'k8s/api/metav1'
|
4
|
-
require 'k8s/api/version'
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
7
|
-
require 'k8s/logging'
|
8
|
-
|
9
|
-
require 'k8s/api_client'
|
10
|
-
require "k8s/client"
|
11
|
-
require "k8s/error"
|
12
|
-
require 'k8s/resource'
|
13
|
-
require 'k8s/resource_client'
|
14
|
-
require 'k8s/stack'
|
15
|
-
require 'k8s/transport'
|
16
|
-
require 'k8s/util'
|
17
|
-
end
|
3
|
+
require_relative 'k8s/client'
|
data/lib/k8s/api.rb
CHANGED
data/lib/k8s/api/metav1.rb
CHANGED
data/lib/k8s/api/metav1/list.rb
CHANGED
data/lib/k8s/api/version.rb
CHANGED
data/lib/k8s/api_client.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module K8s
|
2
4
|
# Per-APIGroup/version client.
|
3
5
|
#
|
@@ -11,7 +13,6 @@ module K8s
|
|
11
13
|
else
|
12
14
|
File.join('/api', api_version)
|
13
15
|
end
|
14
|
-
|
15
16
|
end
|
16
17
|
|
17
18
|
# @param transport [K8s::Transport]
|
@@ -22,9 +23,7 @@ module K8s
|
|
22
23
|
end
|
23
24
|
|
24
25
|
# @return [String]
|
25
|
-
|
26
|
-
@api_version
|
27
|
-
end
|
26
|
+
attr_reader :api_version
|
28
27
|
|
29
28
|
# @param path [Array<String>] join path from parts
|
30
29
|
# @return [String]
|
@@ -38,17 +37,14 @@ module K8s
|
|
38
37
|
end
|
39
38
|
|
40
39
|
# @param api_resources [Array<K8s::API::MetaV1::APIResource>]
|
41
|
-
|
42
|
-
@api_resources = api_resources
|
43
|
-
end
|
40
|
+
attr_writer :api_resources
|
44
41
|
|
45
42
|
# Force-update APIResources
|
46
43
|
#
|
47
44
|
# @return [Array<K8s::API::MetaV1::APIResource>]
|
48
45
|
def api_resources!
|
49
|
-
@api_resources = @transport.get(
|
50
|
-
|
51
|
-
).resources
|
46
|
+
@api_resources = @transport.get(path,
|
47
|
+
response_class: K8s::API::MetaV1::APIResourceList).resources
|
52
48
|
end
|
53
49
|
|
54
50
|
# Cached APIResources
|
@@ -58,18 +54,20 @@ module K8s
|
|
58
54
|
@api_resources || api_resources!
|
59
55
|
end
|
60
56
|
|
57
|
+
# @param resource_name [String]
|
58
|
+
def find_api_resource(resource_name)
|
59
|
+
found_resource = api_resources.find{ |api_resource| api_resource.name == resource_name }
|
60
|
+
raise K8s::Error::UndefinedResource, "Unknown resource #{resource_name} for #{@api_version}" unless found_resource
|
61
|
+
|
62
|
+
found_resource
|
63
|
+
end
|
64
|
+
|
61
65
|
# @param resource_name [String]
|
62
66
|
# @param namespace [String, nil]
|
63
67
|
# @raise [K8s::Error] unknown resource
|
64
68
|
# @return [K8s::ResourceClient]
|
65
69
|
def resource(resource_name, namespace: nil)
|
66
|
-
|
67
|
-
raise K8s::Error::UndefinedResource, "Unknown resource #{resource_name} for #{@api_version}"
|
68
|
-
end
|
69
|
-
|
70
|
-
ResourceClient.new(@transport, self, api_resource,
|
71
|
-
namespace: namespace,
|
72
|
-
)
|
70
|
+
ResourceClient.new(@transport, self, find_api_resource(resource_name), namespace: namespace)
|
73
71
|
end
|
74
72
|
|
75
73
|
# @param resource [K8s::Resource]
|
@@ -82,13 +80,11 @@ module K8s
|
|
82
80
|
raise K8s::Error::UndefinedResource, "Invalid apiVersion=#{resource.apiVersion} for #{@api_version} client"
|
83
81
|
end
|
84
82
|
|
85
|
-
|
86
|
-
|
87
|
-
end
|
83
|
+
found_resource = api_resources.find{ |api_resource| api_resource.kind == resource.kind }
|
84
|
+
raise K8s::Error::UndefinedResource, "Unknown resource kind=#{resource.kind} for #{@api_version}" unless found_resource
|
88
85
|
|
89
|
-
ResourceClient.new(@transport, self,
|
90
|
-
|
91
|
-
)
|
86
|
+
ResourceClient.new(@transport, self, found_resource,
|
87
|
+
namespace: resource.metadata.namespace || namespace)
|
92
88
|
end
|
93
89
|
|
94
90
|
# TODO: skip non-namespaced resources if namespace is given, or ignore namespace?
|
@@ -96,9 +92,10 @@ module K8s
|
|
96
92
|
# @param namespace [String, nil]
|
97
93
|
# @return [Array<K8s::ResourceClient>]
|
98
94
|
def resources(namespace: nil)
|
99
|
-
api_resources.map{ |api_resource|
|
100
|
-
|
101
|
-
|
95
|
+
api_resources.map{ |api_resource|
|
96
|
+
ResourceClient.new(@transport, self, api_resource,
|
97
|
+
namespace: namespace)
|
98
|
+
}
|
102
99
|
end
|
103
100
|
|
104
101
|
# Pipeline list requests for multiple resource types.
|
@@ -109,9 +106,9 @@ module K8s
|
|
109
106
|
# @param options @see [K8s::ResourceClient#list]
|
110
107
|
# @return [Array<K8s::Resource>]
|
111
108
|
def list_resources(resources = nil, **options)
|
112
|
-
resources ||= self.resources.select
|
109
|
+
resources ||= self.resources.select(&:list?)
|
113
110
|
|
114
|
-
ResourceClient.list(
|
111
|
+
ResourceClient.list(resources, @transport, **options)
|
115
112
|
end
|
116
113
|
end
|
117
114
|
end
|
data/lib/k8s/client.rb
CHANGED
@@ -1,6 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'openssl'
|
2
4
|
require 'base64'
|
3
5
|
|
6
|
+
require 'k8s/api/metav1'
|
7
|
+
require 'k8s/api/version'
|
8
|
+
|
9
|
+
require 'k8s/config'
|
10
|
+
require 'k8s/logging'
|
11
|
+
|
12
|
+
require 'k8s/api_client'
|
13
|
+
require "k8s/error"
|
14
|
+
require 'k8s/resource'
|
15
|
+
require 'k8s/resource_client'
|
16
|
+
require 'k8s/stack'
|
17
|
+
require 'k8s/transport'
|
18
|
+
require 'k8s/util'
|
19
|
+
|
4
20
|
module K8s
|
5
21
|
# @param server [String] http/s URL
|
6
22
|
# @param options [Hash] @see Transport.new
|
@@ -18,8 +34,9 @@ module K8s
|
|
18
34
|
# @param options [Hash] @see Transport.config
|
19
35
|
# @return [K8s::Client]
|
20
36
|
def self.config(config, namespace: nil, **options)
|
21
|
-
new(
|
22
|
-
|
37
|
+
new(
|
38
|
+
Transport.config(config, **options),
|
39
|
+
namespace: namespace
|
23
40
|
)
|
24
41
|
end
|
25
42
|
|
@@ -40,8 +57,9 @@ module K8s
|
|
40
57
|
# @raise [K8s::Error]
|
41
58
|
# @return [K8s::API::Version]
|
42
59
|
def version
|
43
|
-
@transport.get(
|
44
|
-
|
60
|
+
@transport.get(
|
61
|
+
'/version',
|
62
|
+
response_class: K8s::API::Version
|
45
63
|
)
|
46
64
|
end
|
47
65
|
|
@@ -56,9 +74,10 @@ module K8s
|
|
56
74
|
#
|
57
75
|
# @return [Array<String>]
|
58
76
|
def api_groups!
|
59
|
-
@api_groups = @transport.get(
|
60
|
-
|
61
|
-
|
77
|
+
@api_groups = @transport.get(
|
78
|
+
'/apis',
|
79
|
+
response_class: K8s::API::MetaV1::APIGroupList
|
80
|
+
).groups.map{ |api_group| api_group.versions.map(&:groupVersion) }.flatten
|
62
81
|
end
|
63
82
|
|
64
83
|
# Cached /apis preferred group apiVersions
|
@@ -72,14 +91,14 @@ module K8s
|
|
72
91
|
# @param skip_missing [Boolean] return APIClient without api_resources? if 404
|
73
92
|
# @return [Array<APIClient>]
|
74
93
|
def apis(api_versions = nil, prefetch_resources: false, skip_missing: false)
|
75
|
-
api_versions ||= ['v1'] +
|
94
|
+
api_versions ||= ['v1'] + api_groups
|
76
95
|
|
77
96
|
if prefetch_resources
|
78
97
|
# api groups that are missing their api_resources
|
79
98
|
api_paths = api_versions
|
80
|
-
|
81
|
-
|
82
|
-
|
99
|
+
.uniq
|
100
|
+
.reject{ |api_version| api(api_version).api_resources? }
|
101
|
+
.map{ |api_version| APIClient.path(api_version) }
|
83
102
|
|
84
103
|
# load into APIClient.api_resources=
|
85
104
|
@transport.gets(*api_paths, response_class: K8s::API::MetaV1::APIResourceList, skip_missing: skip_missing).each do |api_resource_list|
|
@@ -87,7 +106,7 @@ module K8s
|
|
87
106
|
end
|
88
107
|
end
|
89
108
|
|
90
|
-
api_versions.map{|api_version| api(api_version) }
|
109
|
+
api_versions.map{ |api_version| api(api_version) }
|
91
110
|
end
|
92
111
|
|
93
112
|
# @param namespace [String, nil]
|
@@ -104,7 +123,7 @@ module K8s
|
|
104
123
|
# @param options @see K8s::ResourceClient#list
|
105
124
|
# @return [Array<K8s::Resource>]
|
106
125
|
def list_resources(resources = nil, **options)
|
107
|
-
resources ||= self.resources.select
|
126
|
+
resources ||= self.resources.select(&:list?)
|
108
127
|
|
109
128
|
ResourceClient.list(resources, @transport, **options)
|
110
129
|
end
|
@@ -137,7 +156,7 @@ module K8s
|
|
137
156
|
# @return [Array<K8s::Resource, nil>] matching resources array 1:1
|
138
157
|
def get_resources(resources)
|
139
158
|
# prefetch api resources, skip missing APIs
|
140
|
-
resource_apis = apis(resources.map
|
159
|
+
resource_apis = apis(resources.map(&:apiVersion), prefetch_resources: true, skip_missing: true)
|
141
160
|
|
142
161
|
# map each resource to excon request options, or nil if resource is not (yet) defined
|
143
162
|
requests = resources.zip(resource_apis).map{ |resource, api_client|
|
@@ -148,7 +167,7 @@ module K8s
|
|
148
167
|
{
|
149
168
|
method: 'GET',
|
150
169
|
path: resource_client.path(resource.metadata.name, namespace: resource.metadata.namespace),
|
151
|
-
response_class: resource_client.resource_class
|
170
|
+
response_class: resource_client.resource_class
|
152
171
|
}
|
153
172
|
}
|
154
173
|
|
data/lib/k8s/client/version.rb
CHANGED
data/lib/k8s/config.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'dry-struct'
|
2
4
|
require 'dry-types'
|
3
5
|
require 'yaml'
|
@@ -11,7 +13,7 @@ module K8s
|
|
11
13
|
transform_keys do |key|
|
12
14
|
case key
|
13
15
|
when String
|
14
|
-
key.
|
16
|
+
key.tr('-', '_').to_sym
|
15
17
|
else
|
16
18
|
key
|
17
19
|
end
|
@@ -20,7 +22,6 @@ module K8s
|
|
20
22
|
|
21
23
|
# @see https://godoc.org/k8s.io/client-go/tools/clientcmd/api/v1#Config
|
22
24
|
class Config < ConfigStruct
|
23
|
-
|
24
25
|
# Common dry-types for config
|
25
26
|
class Types
|
26
27
|
include Dry::Types.module
|
@@ -41,6 +42,12 @@ module K8s
|
|
41
42
|
attribute :cluster, Cluster
|
42
43
|
end
|
43
44
|
|
45
|
+
# structured user auth provider
|
46
|
+
class UserAuthProvider < ConfigStruct
|
47
|
+
attribute :name, Types::String
|
48
|
+
attribute :config, Types::Strict::Hash
|
49
|
+
end
|
50
|
+
|
44
51
|
# structured user
|
45
52
|
class User < ConfigStruct
|
46
53
|
attribute :client_certificate, Types::String.optional.default(nil)
|
@@ -54,7 +61,7 @@ module K8s
|
|
54
61
|
attribute :as_user_extra, Types::Hash.optional.default(nil)
|
55
62
|
attribute :username, Types::String.optional.default(nil)
|
56
63
|
attribute :password, Types::String.optional.default(nil)
|
57
|
-
attribute :auth_provider,
|
64
|
+
attribute :auth_provider, UserAuthProvider.optional.default(nil)
|
58
65
|
attribute :exec, Types::Strict::Hash.optional.default(nil)
|
59
66
|
attribute :extensions, Types::Strict::Array.optional.default(nil)
|
60
67
|
end
|
@@ -93,23 +100,23 @@ module K8s
|
|
93
100
|
# @param path [String]
|
94
101
|
# @return [K8s::Config]
|
95
102
|
def self.load_file(path)
|
96
|
-
|
103
|
+
new(YAML.load_file(path))
|
97
104
|
end
|
98
105
|
|
99
106
|
# TODO: raise error if not found
|
100
107
|
# @return [K8s::Config::Context]
|
101
108
|
def context(name = current_context)
|
102
|
-
contexts.find{|context| context.name == name}.context
|
109
|
+
contexts.find{ |context| context.name == name }.context
|
103
110
|
end
|
104
111
|
|
105
112
|
# @return [K8s::Config::Cluster]
|
106
113
|
def cluster(name = context.cluster)
|
107
|
-
clusters.find{|cluster| cluster.name == name}.cluster
|
114
|
+
clusters.find{ |cluster| cluster.name == name }.cluster
|
108
115
|
end
|
109
116
|
|
110
117
|
# @return [K8s::Config::User]
|
111
118
|
def user(name = context.user)
|
112
|
-
users.find{|user| user.name == name}.user
|
119
|
+
users.find{ |user| user.name == name }.user
|
113
120
|
end
|
114
121
|
end
|
115
122
|
end
|
data/lib/k8s/error.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'forwardable'
|
2
4
|
|
3
5
|
module K8s
|
4
6
|
# Top-level class for all errors raised by this gem.
|
5
7
|
class Error < StandardError
|
6
|
-
|
7
8
|
# Kube API error, related to a HTTP response with a non-2xx code
|
8
9
|
class API < Error
|
9
10
|
extend Forwardable
|
@@ -30,34 +31,34 @@ module K8s
|
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
#
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
34
|
+
BadRequest = Class.new(API).freeze
|
35
|
+
Unauthorized = Class.new(API).freeze
|
36
|
+
Forbidden = Class.new(API).freeze
|
37
|
+
NotFound = Class.new(API).freeze
|
38
|
+
MethodNotAllowed = Class.new(API).freeze
|
39
|
+
Conflict = Class.new(API).freeze # XXX: also AlreadyExists?
|
40
|
+
Invalid = Class.new(API).freeze
|
41
|
+
Timeout = Class.new(API).freeze
|
42
|
+
InternalError = Class.new(API).freeze
|
43
|
+
ServiceUnavailable = Class.new(API).freeze
|
44
|
+
ServerTimeout = Class.new(API).freeze
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
46
|
+
HTTP_STATUS_ERRORS = {
|
47
|
+
400 => BadRequest,
|
48
|
+
401 => Unauthorized,
|
49
|
+
403 => Forbidden,
|
50
|
+
404 => NotFound,
|
51
|
+
405 => MethodNotAllowed,
|
52
|
+
409 => Conflict,
|
53
|
+
422 => Invalid,
|
54
|
+
429 => Timeout,
|
55
|
+
500 => InternalError,
|
56
|
+
503 => ServiceUnavailable,
|
57
|
+
504 => ServerTimeout
|
58
|
+
}.freeze
|
56
59
|
|
57
60
|
# Attempt to create a ResourceClient for an unknown resource type.
|
58
61
|
# The client cannot construct the correct API URL without having the APIResource definition.
|
59
|
-
|
60
|
-
|
61
|
-
end
|
62
|
+
UndefinedResource = Class.new(Error)
|
62
63
|
end
|
63
64
|
end
|