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/lib/k8s/logging.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'logger'
|
2
4
|
|
3
5
|
module K8s
|
@@ -51,8 +53,8 @@ module K8s
|
|
51
53
|
# @return [Logger]
|
52
54
|
def logger(target: LOG_TARGET, level: nil)
|
53
55
|
@logger ||= Logger.new(target).tap do |logger|
|
54
|
-
logger.progname =
|
55
|
-
logger.level = level ||
|
56
|
+
logger.progname = name
|
57
|
+
logger.level = level || log_level || K8s::Logging.log_level || LOG_LEVEL
|
56
58
|
end
|
57
59
|
end
|
58
60
|
end
|
data/lib/k8s/resource.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'deep_merge'
|
2
4
|
require 'recursive-open-struct'
|
3
5
|
require 'hashdiff'
|
@@ -11,7 +13,7 @@ module K8s
|
|
11
13
|
# @param data [Hash]
|
12
14
|
# @return [self]
|
13
15
|
def self.from_json(data)
|
14
|
-
|
16
|
+
new(data)
|
15
17
|
end
|
16
18
|
|
17
19
|
# @param filename [String] file path
|
@@ -27,9 +29,9 @@ module K8s
|
|
27
29
|
|
28
30
|
if stat.directory?
|
29
31
|
# recurse
|
30
|
-
Dir.glob("#{path}/*.{yml,yaml}").sort.map { |dir|
|
32
|
+
Dir.glob("#{path}/*.{yml,yaml}").sort.map { |dir| from_files(dir) }.flatten
|
31
33
|
else
|
32
|
-
::YAML.load_stream(File.read(path), path).map{|doc| new(doc) }
|
34
|
+
::YAML.load_stream(File.read(path), path).map{ |doc| new(doc) }
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
@@ -67,7 +69,7 @@ module K8s
|
|
67
69
|
end
|
68
70
|
|
69
71
|
def checksum
|
70
|
-
@checksum ||= Digest::MD5.hexdigest(Marshal
|
72
|
+
@checksum ||= Digest::MD5.hexdigest(Marshal.dump(to_hash))
|
71
73
|
end
|
72
74
|
|
73
75
|
def merge_patch_ops(attrs, config_annotation)
|
@@ -78,7 +80,7 @@ module K8s
|
|
78
80
|
#
|
79
81
|
# @return [Hash]
|
80
82
|
def current_config(config_annotation)
|
81
|
-
current_cfg =
|
83
|
+
current_cfg = metadata.annotations&.dig(config_annotation)
|
82
84
|
return {} unless current_cfg
|
83
85
|
|
84
86
|
current_hash = JSON.parse(current_cfg)
|
@@ -89,11 +91,11 @@ module K8s
|
|
89
91
|
end
|
90
92
|
|
91
93
|
def can_patch?(config_annotation)
|
92
|
-
!!
|
94
|
+
!!metadata.annotations&.dig(config_annotation)
|
93
95
|
end
|
94
96
|
|
95
97
|
def stringify_hash(hash)
|
96
|
-
JSON.
|
98
|
+
JSON.parse(JSON.dump(hash))
|
97
99
|
end
|
98
100
|
end
|
99
101
|
end
|
data/lib/k8s/resource_client.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module K8s
|
2
4
|
# Per-APIResource type client.
|
3
5
|
#
|
4
6
|
# Used to get/list/update/patch/delete specific types of resources, optionally in some specific namespace.
|
5
7
|
class ResourceClient
|
6
|
-
|
7
8
|
# Common helpers used in both class/instance methods
|
8
9
|
module Utils
|
9
10
|
# @param selector [nil, String, Hash{String => String}]
|
@@ -15,7 +16,7 @@ module K8s
|
|
15
16
|
when String
|
16
17
|
selector
|
17
18
|
when Hash
|
18
|
-
selector.map{|k, v| "#{k}=#{v}"}.join ','
|
19
|
+
selector.map{ |k, v| "#{k}=#{v}" }.join ','
|
19
20
|
else
|
20
21
|
fail "Invalid selector type. #{selector.inspect}"
|
21
22
|
end
|
@@ -47,17 +48,18 @@ module K8s
|
|
47
48
|
# @param skip_forbidden [Boolean] skip resources that return HTTP 403 errors
|
48
49
|
# @return [Array<K8s::Resource>]
|
49
50
|
def self.list(resources, transport, namespace: nil, labelSelector: nil, fieldSelector: nil, skip_forbidden: false)
|
50
|
-
api_paths = resources.map{|resource| resource.path(namespace: namespace) }
|
51
|
-
api_lists = transport.gets(
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
51
|
+
api_paths = resources.map{ |resource| resource.path(namespace: namespace) }
|
52
|
+
api_lists = transport.gets(
|
53
|
+
*api_paths,
|
54
|
+
response_class: K8s::API::MetaV1::List,
|
55
|
+
query: make_query(
|
56
|
+
'labelSelector' => selector_query(labelSelector),
|
57
|
+
'fieldSelector' => selector_query(fieldSelector)
|
58
|
+
),
|
59
|
+
skip_forbidden: skip_forbidden
|
60
|
+
)
|
61
|
+
|
62
|
+
resources.zip(api_lists).map { |resource, api_list| api_list ? resource.process_list(api_list) : [] }.flatten
|
61
63
|
end
|
62
64
|
|
63
65
|
# @param transport [K8s::Transport]
|
@@ -78,7 +80,7 @@ module K8s
|
|
78
80
|
@subresource = nil
|
79
81
|
end
|
80
82
|
|
81
|
-
fail "Resource #{api_resource.name} is not namespaced"
|
83
|
+
fail "Resource #{api_resource.name} is not namespaced" unless api_resource.namespaced || !namespace
|
82
84
|
end
|
83
85
|
|
84
86
|
# @return [String]
|
@@ -92,14 +94,10 @@ module K8s
|
|
92
94
|
end
|
93
95
|
|
94
96
|
# @return [String, nil]
|
95
|
-
|
96
|
-
@namespace
|
97
|
-
end
|
97
|
+
attr_reader :namespace
|
98
98
|
|
99
99
|
# @return [String]
|
100
|
-
|
101
|
-
@resource
|
102
|
-
end
|
100
|
+
attr_reader :resource
|
103
101
|
|
104
102
|
# @return [Boolean]
|
105
103
|
def subresource?
|
@@ -107,9 +105,7 @@ module K8s
|
|
107
105
|
end
|
108
106
|
|
109
107
|
# @return [String, nil]
|
110
|
-
|
111
|
-
@subresource
|
112
|
-
end
|
108
|
+
attr_reader :subresource
|
113
109
|
|
114
110
|
# @return [String]
|
115
111
|
def kind
|
@@ -117,9 +113,7 @@ module K8s
|
|
117
113
|
end
|
118
114
|
|
119
115
|
# @return [class] K8s::Resource
|
120
|
-
|
121
|
-
@resource_class
|
122
|
-
end
|
116
|
+
attr_reader :resource_class
|
123
117
|
|
124
118
|
# @return [Bool]
|
125
119
|
def namespaced?
|
@@ -149,9 +143,9 @@ module K8s
|
|
149
143
|
def create_resource(resource)
|
150
144
|
@transport.request(
|
151
145
|
method: 'POST',
|
152
|
-
path:
|
146
|
+
path: path(namespace: resource.metadata.namespace),
|
153
147
|
request_object: resource,
|
154
|
-
response_class: @resource_class
|
148
|
+
response_class: @resource_class
|
155
149
|
)
|
156
150
|
end
|
157
151
|
|
@@ -164,8 +158,8 @@ module K8s
|
|
164
158
|
def get(name, namespace: @namespace)
|
165
159
|
@transport.request(
|
166
160
|
method: 'GET',
|
167
|
-
path:
|
168
|
-
response_class: @resource_class
|
161
|
+
path: path(name, namespace: namespace),
|
162
|
+
response_class: @resource_class
|
169
163
|
)
|
170
164
|
end
|
171
165
|
|
@@ -174,8 +168,8 @@ module K8s
|
|
174
168
|
def get_resource(resource)
|
175
169
|
@transport.request(
|
176
170
|
method: 'GET',
|
177
|
-
path:
|
178
|
-
response_class: @resource_class
|
171
|
+
path: path(resource.metadata.name, namespace: resource.metadata.namespace),
|
172
|
+
response_class: @resource_class
|
179
173
|
)
|
180
174
|
end
|
181
175
|
|
@@ -187,7 +181,7 @@ module K8s
|
|
187
181
|
# @param list [K8s::API::MetaV1::List]
|
188
182
|
# @return [Array<resource_class>]
|
189
183
|
def process_list(list)
|
190
|
-
list.items.map {|item|
|
184
|
+
list.items.map { |item|
|
191
185
|
# list items omit kind/apiVersion
|
192
186
|
@resource_class.new(item.merge('apiVersion' => list.apiVersion, 'kind' => @api_resource.kind))
|
193
187
|
}
|
@@ -199,12 +193,12 @@ module K8s
|
|
199
193
|
def list(labelSelector: nil, fieldSelector: nil, namespace: @namespace)
|
200
194
|
list = @transport.request(
|
201
195
|
method: 'GET',
|
202
|
-
path:
|
196
|
+
path: path(namespace: namespace),
|
203
197
|
response_class: K8s::API::MetaV1::List,
|
204
198
|
query: make_query(
|
205
199
|
'labelSelector' => selector_query(labelSelector),
|
206
|
-
'fieldSelector' => selector_query(fieldSelector)
|
207
|
-
)
|
200
|
+
'fieldSelector' => selector_query(fieldSelector)
|
201
|
+
)
|
208
202
|
)
|
209
203
|
process_list(list)
|
210
204
|
end
|
@@ -219,9 +213,9 @@ module K8s
|
|
219
213
|
def update_resource(resource)
|
220
214
|
@transport.request(
|
221
215
|
method: 'PUT',
|
222
|
-
path:
|
216
|
+
path: path(resource.metadata.name, namespace: resource.metadata.namespace),
|
223
217
|
request_object: resource,
|
224
|
-
response_class: @resource_class
|
218
|
+
response_class: @resource_class
|
225
219
|
)
|
226
220
|
end
|
227
221
|
|
@@ -238,10 +232,10 @@ module K8s
|
|
238
232
|
def merge_patch(name, obj, namespace: @namespace, strategic_merge: true)
|
239
233
|
@transport.request(
|
240
234
|
method: 'PATCH',
|
241
|
-
path:
|
235
|
+
path: path(name, namespace: namespace),
|
242
236
|
content_type: strategic_merge ? 'application/strategic-merge-patch+json' : 'application/merge-patch+json',
|
243
237
|
request_object: obj,
|
244
|
-
response_class: @resource_class
|
238
|
+
response_class: @resource_class
|
245
239
|
)
|
246
240
|
end
|
247
241
|
|
@@ -252,10 +246,10 @@ module K8s
|
|
252
246
|
def json_patch(name, ops, namespace: @namespace)
|
253
247
|
@transport.request(
|
254
248
|
method: 'PATCH',
|
255
|
-
path:
|
249
|
+
path: path(name, namespace: namespace),
|
256
250
|
content_type: 'application/json-patch+json',
|
257
251
|
request_object: ops,
|
258
|
-
response_class: @resource_class
|
252
|
+
response_class: @resource_class
|
259
253
|
)
|
260
254
|
end
|
261
255
|
|
@@ -271,7 +265,7 @@ module K8s
|
|
271
265
|
def delete(name, namespace: @namespace, propagationPolicy: nil)
|
272
266
|
@transport.request(
|
273
267
|
method: 'DELETE',
|
274
|
-
path:
|
268
|
+
path: path(name, namespace: namespace),
|
275
269
|
query: make_query(
|
276
270
|
'propagationPolicy' => propagationPolicy
|
277
271
|
),
|
@@ -286,11 +280,11 @@ module K8s
|
|
286
280
|
def delete_collection(namespace: @namespace, labelSelector: nil, fieldSelector: nil, propagationPolicy: nil)
|
287
281
|
list = @transport.request(
|
288
282
|
method: 'DELETE',
|
289
|
-
path:
|
283
|
+
path: path(namespace: namespace),
|
290
284
|
query: make_query(
|
291
285
|
'labelSelector' => selector_query(labelSelector),
|
292
286
|
'fieldSelector' => selector_query(fieldSelector),
|
293
|
-
'propagationPolicy' => propagationPolicy
|
287
|
+
'propagationPolicy' => propagationPolicy
|
294
288
|
),
|
295
289
|
response_class: K8s::API::MetaV1::List, # XXX: documented as returning Status
|
296
290
|
)
|
data/lib/k8s/stack.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'securerandom'
|
2
4
|
|
3
5
|
module K8s
|
@@ -19,7 +21,7 @@ module K8s
|
|
19
21
|
PRUNE_IGNORE = [
|
20
22
|
'v1:ComponentStatus', # apiserver ignores GET /v1/componentstatuses?labelSelector=... and returns all resources
|
21
23
|
'v1:Endpoints', # inherits stack label from service, but not checksum annotation
|
22
|
-
]
|
24
|
+
].freeze
|
23
25
|
|
24
26
|
# @param name [String] unique name for stack
|
25
27
|
# @param path [String] load resources from YAML files
|
@@ -59,23 +61,27 @@ module K8s
|
|
59
61
|
end
|
60
62
|
|
61
63
|
# @param resource [K8s::Resource] to apply
|
62
|
-
# @param base_resource [K8s::Resource]
|
64
|
+
# @param base_resource [K8s::Resource] DEPRECATED
|
63
65
|
# @return [K8s::Resource]
|
66
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
64
67
|
def prepare_resource(resource, base_resource: nil)
|
65
|
-
#
|
68
|
+
# TODO: base_resource is not used anymore, kept for backwards compatibility for a while
|
66
69
|
|
67
70
|
# calculate checksum only from the "local" source
|
68
71
|
checksum = resource.checksum
|
69
72
|
|
70
73
|
# add stack metadata
|
71
|
-
resource.merge(
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
74
|
+
resource.merge(
|
75
|
+
metadata: {
|
76
|
+
labels: { @label => name },
|
77
|
+
annotations: {
|
78
|
+
@checksum_annotation => checksum,
|
79
|
+
@last_config_annotation => resource.to_json
|
80
|
+
}
|
81
|
+
}
|
82
|
+
)
|
78
83
|
end
|
84
|
+
# rubocop:enable Lint/UnusedMethodArgument
|
79
85
|
|
80
86
|
# @return [Array<K8s::Resource>]
|
81
87
|
def apply(client, prune: true)
|
@@ -107,14 +113,15 @@ module K8s
|
|
107
113
|
def keep_resource!(resource)
|
108
114
|
@keep_resources["#{resource.kind}:#{resource.metadata.name}@#{resource.metadata.namespace}"] = resource.metadata.annotations[@checksum_annotation]
|
109
115
|
end
|
116
|
+
|
110
117
|
def keep_resource?(resource)
|
111
118
|
@keep_resources["#{resource.kind}:#{resource.metadata.name}@#{resource.metadata.namespace}"] == resource.metadata.annotations[@checksum_annotation]
|
112
119
|
end
|
113
120
|
|
114
121
|
# Delete all stack resources that were not applied
|
115
|
-
def prune(client, keep_resources
|
122
|
+
def prune(client, keep_resources:, skip_forbidden: true)
|
116
123
|
# using skip_forbidden: assume we can't create resource types that we are forbidden to list, so we don't need to prune them either
|
117
|
-
client.list_resources(labelSelector: {@label => name}, skip_forbidden: skip_forbidden).sort
|
124
|
+
client.list_resources(labelSelector: { @label => name }, skip_forbidden: skip_forbidden).sort do |a, b|
|
118
125
|
# Sort resources so that namespaced objects are deleted first
|
119
126
|
if a.metadata.namespace == b.metadata.namespace
|
120
127
|
0
|
@@ -123,7 +130,7 @@ module K8s
|
|
123
130
|
else
|
124
131
|
-1
|
125
132
|
end
|
126
|
-
|
133
|
+
end.each do |resource|
|
127
134
|
next if PRUNE_IGNORE.include? "#{resource.apiVersion}:#{resource.kind}"
|
128
135
|
|
129
136
|
resource_label = resource.metadata.labels ? resource.metadata.labels[@label] : nil
|
@@ -139,9 +146,10 @@ module K8s
|
|
139
146
|
logger.info "Delete resource #{resource.apiVersion}:#{resource.kind}/#{resource.metadata.name} in namespace #{resource.metadata.namespace}"
|
140
147
|
begin
|
141
148
|
client.delete_resource(resource, propagationPolicy: 'Background')
|
142
|
-
rescue K8s::Error::NotFound
|
149
|
+
rescue K8s::Error::NotFound => ex
|
143
150
|
# assume aliased objects in multiple API groups, like for Deployments
|
144
151
|
# alternatively, a custom resource whose definition was already deleted earlier
|
152
|
+
logger.debug { "Ignoring #{ex} : #{ex.message}" }
|
145
153
|
end
|
146
154
|
end
|
147
155
|
end
|
data/lib/k8s/transport.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'excon'
|
2
4
|
require 'json'
|
5
|
+
require 'jsonpath'
|
3
6
|
|
4
7
|
module K8s
|
5
8
|
# Excon-based HTTP transport handling request/response body JSON encoding
|
@@ -11,13 +14,13 @@ module K8s
|
|
11
14
|
# Excon middlewares for requests
|
12
15
|
EXCON_MIDDLEWARES = [
|
13
16
|
# XXX: necessary? redirected requests omit authz headers?
|
14
|
-
Excon::Middleware::RedirectFollower
|
17
|
+
Excon::Middleware::RedirectFollower
|
15
18
|
] + Excon.defaults[:middlewares]
|
16
19
|
|
17
20
|
# Default request headers
|
18
21
|
REQUEST_HEADERS = {
|
19
|
-
'Accept' => 'application/json'
|
20
|
-
}
|
22
|
+
'Accept' => 'application/json'
|
23
|
+
}.freeze
|
21
24
|
|
22
25
|
# Construct transport from kubeconfig
|
23
26
|
#
|
@@ -67,6 +70,16 @@ module K8s
|
|
67
70
|
logger.debug "Using config with .user.token=..."
|
68
71
|
|
69
72
|
options[:auth_token] = token
|
73
|
+
elsif config.user.auth_provider && auth_provider = config.user.auth_provider.config
|
74
|
+
logger.debug "Using config with .user.auth-provider.name=#{config.user.auth_provider.name}"
|
75
|
+
|
76
|
+
auth_data = `#{auth_provider['cmd-path']} #{auth_provider['cmd-args']}`.strip
|
77
|
+
if auth_provider['token-key']
|
78
|
+
json_path = JsonPath.new(auth_provider['token-key'][1...-1])
|
79
|
+
options[:auth_token] = json_path.first(auth_data)
|
80
|
+
else
|
81
|
+
options[:auth_token] = auth_data
|
82
|
+
end
|
70
83
|
end
|
71
84
|
|
72
85
|
logger.info "Using config with server=#{server}"
|
@@ -81,10 +94,11 @@ module K8s
|
|
81
94
|
host = ENV['KUBERNETES_SERVICE_HOST']
|
82
95
|
port = ENV['KUBERNETES_SERVICE_PORT_HTTPS']
|
83
96
|
|
84
|
-
new(
|
97
|
+
new(
|
98
|
+
"https://#{host}:#{port}",
|
85
99
|
ssl_verify_peer: true,
|
86
100
|
ssl_ca_file: '/var/run/secrets/kubernetes.io/serviceaccount/ca.crt',
|
87
|
-
auth_token: File.read('/var/run/secrets/kubernetes.io/serviceaccount/token')
|
101
|
+
auth_token: File.read('/var/run/secrets/kubernetes.io/serviceaccount/token')
|
88
102
|
)
|
89
103
|
end
|
90
104
|
|
@@ -103,7 +117,8 @@ module K8s
|
|
103
117
|
|
104
118
|
# @return [Excon::Connection]
|
105
119
|
def excon
|
106
|
-
@excon ||= Excon.new(
|
120
|
+
@excon ||= Excon.new(
|
121
|
+
@server,
|
107
122
|
persistent: true,
|
108
123
|
middlewares: EXCON_MIDDLEWARES,
|
109
124
|
headers: REQUEST_HEADERS,
|
@@ -145,6 +160,7 @@ module K8s
|
|
145
160
|
if options[:query]
|
146
161
|
path += Excon::Utils.query_string(options)
|
147
162
|
end
|
163
|
+
|
148
164
|
if obj = options[:request_object]
|
149
165
|
body = "<#{obj.class.name}>"
|
150
166
|
end
|
@@ -178,11 +194,9 @@ module K8s
|
|
178
194
|
raise K8s::Error::API.new(method, path, response.status, "Invalid JSON response: #{response_data.inspect}")
|
179
195
|
end
|
180
196
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
return response_data # Hash
|
185
|
-
end
|
197
|
+
return response_data unless response_class
|
198
|
+
|
199
|
+
response_class.from_json(response_data)
|
186
200
|
else
|
187
201
|
error_class = K8s::Error::HTTP_STATUS_ERRORS[response.status] || K8s::Error::API
|
188
202
|
|
@@ -208,18 +222,17 @@ module K8s
|
|
208
222
|
t = Time.now - start
|
209
223
|
|
210
224
|
obj = parse_response(response, options,
|
211
|
-
|
212
|
-
)
|
225
|
+
response_class: response_class)
|
213
226
|
rescue K8s::Error::API => exc
|
214
|
-
logger.warn { "#{format_request(options)} => HTTP #{exc.code} #{exc.reason} in #{'%.3f' % t}s"}
|
215
|
-
logger.debug { "Request: #{excon_options[:body]}"} if excon_options[:body]
|
216
|
-
logger.debug { "Response: #{response.body}"}
|
227
|
+
logger.warn { "#{format_request(options)} => HTTP #{exc.code} #{exc.reason} in #{'%.3f' % t}s" }
|
228
|
+
logger.debug { "Request: #{excon_options[:body]}" } if excon_options[:body]
|
229
|
+
logger.debug { "Response: #{response.body}" }
|
217
230
|
raise
|
218
231
|
else
|
219
|
-
logger.info { "#{format_request(options)} => HTTP #{response.status}: <#{obj.class}> in #{'%.3f' % t}s"}
|
220
|
-
logger.debug { "Request: #{excon_options[:body]}"} if excon_options[:body]
|
221
|
-
logger.debug { "Response: #{response.body}"}
|
222
|
-
|
232
|
+
logger.info { "#{format_request(options)} => HTTP #{response.status}: <#{obj.class}> in #{'%.3f' % t}s" }
|
233
|
+
logger.debug { "Request: #{excon_options[:body]}" } if excon_options[:body]
|
234
|
+
logger.debug { "Response: #{response.body}" }
|
235
|
+
obj
|
223
236
|
end
|
224
237
|
|
225
238
|
# @param options [Array<Hash>] @see #request
|
@@ -233,46 +246,39 @@ module K8s
|
|
233
246
|
|
234
247
|
start = Time.now
|
235
248
|
responses = excon.requests(
|
236
|
-
options.map{|
|
249
|
+
options.map{ |opts| request_options(**common_options.merge(opts)) }
|
237
250
|
)
|
238
251
|
t = Time.now - start
|
239
252
|
|
240
|
-
objects = responses.zip(options).map{|response, request_options|
|
253
|
+
objects = responses.zip(options).map{ |response, request_options|
|
241
254
|
response_class = request_options[:response_class] || common_options[:response_class]
|
242
255
|
|
243
256
|
begin
|
244
257
|
parse_response(response, request_options,
|
245
|
-
|
246
|
-
)
|
258
|
+
response_class: response_class)
|
247
259
|
rescue K8s::Error::NotFound
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
raise
|
252
|
-
end
|
260
|
+
raise unless skip_missing
|
261
|
+
|
262
|
+
nil
|
253
263
|
rescue K8s::Error::Forbidden
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
raise
|
258
|
-
end
|
264
|
+
raise unless skip_forbidden
|
265
|
+
|
266
|
+
nil
|
259
267
|
rescue K8s::Error::ServiceUnavailable => exc
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
raise
|
267
|
-
end
|
268
|
+
raise unless retry_errors
|
269
|
+
|
270
|
+
logger.warn { "Retry #{format_request(request_options)} => HTTP #{exc.code} #{exc.reason} in #{'%.3f' % t}s" }
|
271
|
+
|
272
|
+
# only retry the failed request, not the entire pipeline
|
273
|
+
request(response_class: response_class, **common_options.merge(request_options))
|
268
274
|
end
|
269
275
|
}
|
270
276
|
rescue K8s::Error => exc
|
271
|
-
logger.warn { "[#{options.map{|o| format_request(o)}.join ', '}] => HTTP #{exc.code} #{exc.reason} in #{'%.3f' % t}s"}
|
277
|
+
logger.warn { "[#{options.map{ |o| format_request(o) }.join ', '}] => HTTP #{exc.code} #{exc.reason} in #{'%.3f' % t}s" }
|
272
278
|
raise
|
273
279
|
else
|
274
|
-
logger.info { "[#{options.map{|o| format_request(o)}.join ', '}] => HTTP [#{responses.map
|
275
|
-
|
280
|
+
logger.info { "[#{options.map{ |o| format_request(o) }.join ', '}] => HTTP [#{responses.map(&:status).join ', '}] in #{'%.3f' % t}s" }
|
281
|
+
objects
|
276
282
|
end
|
277
283
|
|
278
284
|
# @param path [Array<String>] @see #path
|
@@ -281,17 +287,20 @@ module K8s
|
|
281
287
|
request(
|
282
288
|
method: 'GET',
|
283
289
|
path: self.path(*path),
|
284
|
-
**options
|
290
|
+
**options
|
285
291
|
)
|
286
292
|
end
|
287
293
|
|
288
294
|
# @param paths [Array<String>]
|
289
295
|
# @param options [Hash] @see #request
|
290
296
|
def gets(*paths, **options)
|
291
|
-
requests(
|
292
|
-
|
293
|
-
|
294
|
-
|
297
|
+
requests(
|
298
|
+
*paths.map do |path|
|
299
|
+
{
|
300
|
+
method: 'GET',
|
301
|
+
path: self.path(path)
|
302
|
+
}
|
303
|
+
end,
|
295
304
|
**options
|
296
305
|
)
|
297
306
|
end
|