kube_cluster 0.20.1 → 1.0.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 +1 -0
- data/CHANGELOG.md +34 -0
- data/Gemfile.lock +5 -37
- data/flake.nix +2 -1
- data/kube_cluster.gemspec +2 -4
- data/lib/kube/cluster/container.rb +17 -17
- data/lib/kube/cluster/manifest.rb +158 -158
- data/lib/kube/cluster/middleware/annotations.rb +42 -42
- data/lib/kube/cluster/middleware/hpa_for_deployment.rb +134 -134
- data/lib/kube/cluster/middleware/ingress_for_service.rb +75 -75
- data/lib/kube/cluster/middleware/labels.rb +58 -58
- data/lib/kube/cluster/middleware/pod_anti_affinity.rb +104 -104
- data/lib/kube/cluster/middleware/resource_preset.rb +145 -145
- data/lib/kube/cluster/middleware/security_context.rb +127 -127
- data/lib/kube/cluster/middleware/service_for_deployment.rb +120 -120
- data/lib/kube/cluster/middleware.rb +219 -221
- data/lib/kube/cluster/resource/dirty_tracking.rb +388 -388
- data/lib/kube/cluster/resource.rb +16 -16
- data/lib/kube/cluster/standard/cdi/data_volume.rb +13 -13
- data/lib/kube/cluster/standard/cloud_native_pg/cluster.rb +11 -11
- data/lib/kube/cluster/standard/cloud_native_pg/database_with_external_secret.rb +11 -11
- data/lib/kube/cluster/standard/cloud_native_pg/external_secret.rb +11 -11
- data/lib/kube/cluster/standard/cloud_native_pg/helm.rb +26 -26
- data/lib/kube/cluster/standard/config_map.rb +11 -11
- data/lib/kube/cluster/standard/cron_job.rb +13 -13
- data/lib/kube/cluster/standard/cron_job_with_service_account.rb +12 -12
- data/lib/kube/cluster/standard/custom_resource_definition.rb +12 -12
- data/lib/kube/cluster/standard/daemon_set.rb +12 -12
- data/lib/kube/cluster/standard/deployment_with_service.rb +82 -82
- data/lib/kube/cluster/standard/env_processing.rb +15 -15
- data/lib/kube/cluster/standard/eso/external_secret.rb +13 -13
- data/lib/kube/cluster/standard/forgejo/helm.rb +11 -11
- data/lib/kube/cluster/standard/gateway_api/http_route.rb +322 -19
- data/lib/kube/cluster/standard/job.rb +12 -12
- data/lib/kube/cluster/standard/job_with_service_account.rb +11 -11
- data/lib/kube/cluster/standard/kube_virt/virtual_machine.rb +11 -11
- data/lib/kube/cluster/standard/meta_controller/composite_controller.rb +13 -13
- data/lib/kube/cluster/standard/meta_controller/decorator_controller.rb +13 -13
- data/lib/kube/cluster/standard/perses/perses.rb +9 -9
- data/lib/kube/cluster/standard/perses/perses_datasource.rb +13 -13
- data/lib/kube/cluster/standard/persistent_volume_claim.rb +12 -12
- data/lib/kube/cluster/standard/role.rb +12 -12
- data/lib/kube/cluster/standard/role_binding.rb +10 -10
- data/lib/kube/cluster/standard/secret.rb +11 -11
- data/lib/kube/cluster/standard/service.rb +12 -12
- data/lib/kube/cluster/standard/service_account.rb +9 -9
- data/lib/kube/cluster/standard/service_account_with_role.rb +10 -10
- data/lib/kube/cluster/standard/victoria_metrics/vl_agent.rb +9 -9
- data/lib/kube/cluster/standard/victoria_metrics/vl_single.rb +9 -9
- data/lib/kube/cluster/standard/victoria_metrics/vm_agent.rb +9 -9
- data/lib/kube/cluster/standard/victoria_metrics/vm_node_scrape.rb +9 -9
- data/lib/kube/cluster/standard/victoria_metrics/vm_service_scrape.rb +9 -9
- data/lib/kube/cluster/standard/victoria_metrics/vm_single.rb +9 -9
- data/lib/kube/cluster/standard/volume_processing.rb +3 -3
- data/lib/kube/cluster/version.rb +1 -1
- data/lib/kube/cluster.rb +137 -1
- data/lib/kube/helm/chart.rb +323 -323
- data/lib/kube/helm/endpoint.rb +58 -58
- data/lib/kube/helm/repo.rb +160 -160
- metadata +7 -20
|
@@ -4,30 +4,333 @@ require "bundler/setup"
|
|
|
4
4
|
require "kube/cluster"
|
|
5
5
|
|
|
6
6
|
module Kube
|
|
7
|
-
module Cluster
|
|
7
|
+
module Cluster
|
|
8
8
|
module Standard
|
|
9
9
|
module GatewayApi
|
|
10
|
-
#
|
|
11
|
-
#
|
|
10
|
+
# A single-rule HTTPRoute attached to the cluster's one traefik-gateway.
|
|
11
|
+
#
|
|
12
|
+
# Every route in ns/ shares the same parentRefs (the `traefik-gateway`
|
|
13
|
+
# in kube-system) and differs only by listener section, host(s), the
|
|
14
|
+
# backing Service, the path matches, and an optional chain of traefik
|
|
15
|
+
# middlewares. This collapses that boilerplate to a keyword call.
|
|
16
|
+
#
|
|
17
|
+
# Deliberately models exactly ONE rule: one set of matches -> one
|
|
18
|
+
# backend (or a terminal redirect), with one filter chain. Routes that
|
|
19
|
+
# need distinct backends or filters per path (fanout) are expressed as
|
|
20
|
+
# several instances on the same host -- the gateway merges them and the
|
|
21
|
+
# more-specific match wins.
|
|
22
|
+
#
|
|
23
|
+
# Standard::GatewayApi::HTTPRoute.new(
|
|
24
|
+
# name: "sourcebot",
|
|
25
|
+
# gateway: "example-com-https",
|
|
26
|
+
# domains: ["sg.example.com"],
|
|
27
|
+
# service: { namespace: "sourcebot", name: "sourcebot", port: 3000 },
|
|
28
|
+
# middleware: "forwardauth-oauth2-proxy-example",
|
|
29
|
+
# )
|
|
30
|
+
#
|
|
31
|
+
# Many matches -> one backend (forgejo git smart-HTTP):
|
|
32
|
+
#
|
|
33
|
+
# Standard::GatewayApi::HTTPRoute.new(
|
|
34
|
+
# name: "forgejo-git", gateway: "example-net-https", domains: ["git.example.net"],
|
|
35
|
+
# regex: ["/.+/info/refs", "/.+/git-upload-pack", "/.+/git-receive-pack"],
|
|
36
|
+
# prefix: ["/api", "/v2"],
|
|
37
|
+
# service: { namespace: "default", name: "forgejo-http", port: 3000 },
|
|
38
|
+
# timeouts: { request: "600s", backendRequest: "600s" },
|
|
39
|
+
# )
|
|
40
|
+
#
|
|
41
|
+
# Terminal http->https redirect (the `-http` sibling):
|
|
42
|
+
#
|
|
43
|
+
# Standard::GatewayApi::HTTPRoute.new(
|
|
44
|
+
# name: "sourcebot-http", gateway: "example-com-http",
|
|
45
|
+
# domains: ["sg.example.com"], prefix: ["/"], redirect: true,
|
|
46
|
+
# )
|
|
47
|
+
class HTTPRoute < Kube::Cluster["HTTPRoute"]
|
|
48
|
+
GATEWAY_GROUP = "gateway.networking.k8s.io"
|
|
49
|
+
GATEWAY_NAME = "traefik-gateway"
|
|
50
|
+
GATEWAY_NS = "kube-system"
|
|
51
|
+
|
|
52
|
+
# traefik middlewares are attached to a rule via an ExtensionRef filter.
|
|
53
|
+
MIDDLEWARE_GROUP = "traefik.io"
|
|
54
|
+
MIDDLEWARE_KIND = "Middleware"
|
|
55
|
+
|
|
56
|
+
PATH_TYPES = {
|
|
57
|
+
prefix: "PathPrefix",
|
|
58
|
+
exact: "Exact",
|
|
59
|
+
regex: "RegularExpression",
|
|
60
|
+
}.freeze
|
|
61
|
+
|
|
62
|
+
def initialize(
|
|
63
|
+
name:,
|
|
64
|
+
gateway:,
|
|
65
|
+
domains:,
|
|
66
|
+
service: nil,
|
|
67
|
+
prefix: nil,
|
|
68
|
+
exact: nil,
|
|
69
|
+
regex: nil,
|
|
70
|
+
headers: nil,
|
|
71
|
+
middleware: nil,
|
|
72
|
+
redirect: nil,
|
|
73
|
+
header_modifier: nil,
|
|
74
|
+
timeouts: nil,
|
|
75
|
+
namespace: "kube-system",
|
|
76
|
+
&block
|
|
77
|
+
)
|
|
78
|
+
hostnames = Array(domains)
|
|
79
|
+
matches = _matches(prefix: prefix, exact: exact, regex: regex, headers: headers)
|
|
80
|
+
filters = _filters(middleware: middleware, redirect: redirect, header_modifier: header_modifier)
|
|
81
|
+
|
|
82
|
+
rule = { matches: matches }
|
|
83
|
+
rule[:filters] = filters unless filters.empty?
|
|
84
|
+
rule[:backendRefs] = [_backend(service)] if service
|
|
85
|
+
rule[:timeouts] = timeouts if timeouts
|
|
86
|
+
|
|
87
|
+
super() {
|
|
88
|
+
metadata.name = name
|
|
89
|
+
# A co-located route (namespace: nil) omits metadata.namespace so
|
|
90
|
+
# it lands in whatever namespace applies it; cross-namespace routes
|
|
91
|
+
# in kube-system set it explicitly.
|
|
92
|
+
metadata.namespace = namespace if namespace
|
|
93
|
+
|
|
94
|
+
spec.hostnames = hostnames
|
|
95
|
+
spec.parentRefs = [{
|
|
96
|
+
group: GATEWAY_GROUP,
|
|
97
|
+
kind: "Gateway",
|
|
98
|
+
name: GATEWAY_NAME,
|
|
99
|
+
namespace: GATEWAY_NS,
|
|
100
|
+
sectionName: gateway,
|
|
101
|
+
}]
|
|
102
|
+
spec.rules = [rule]
|
|
103
|
+
|
|
104
|
+
instance_exec(&block) if block_given?
|
|
105
|
+
}
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
# Build the rule's `matches`: one entry per path across the typed
|
|
111
|
+
# arrays, all sharing the single backend. A path match is mandatory --
|
|
112
|
+
# every route (including a redirect-only one) must state its path, so
|
|
113
|
+
# this raises rather than silently assuming `/` when none is given.
|
|
114
|
+
def _matches(prefix:, exact:, regex:, headers:)
|
|
115
|
+
entries = []
|
|
116
|
+
{ prefix: prefix, exact: exact, regex: regex }.each do |kind, values|
|
|
117
|
+
Array(values).each do |value|
|
|
118
|
+
entries << { path: { type: PATH_TYPES.fetch(kind), value: value } }
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
if entries.empty?
|
|
122
|
+
raise ArgumentError,
|
|
123
|
+
"HTTPRoute requires at least one path match: pass prefix:, exact:, or regex:"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
hdrs = _headers(headers)
|
|
127
|
+
hdrs.empty? ? entries : entries.map { |m| m.merge(headers: hdrs) }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Accepts either a { "Header" => "value" } hash (Exact match) or a
|
|
131
|
+
# ready-made array of Gateway API header-match hashes.
|
|
132
|
+
def _headers(headers)
|
|
133
|
+
return [] if headers.nil? || headers.empty?
|
|
134
|
+
return headers if headers.is_a?(Array)
|
|
135
|
+
|
|
136
|
+
headers.map { |name, value| { type: "Exact", name: name.to_s, value: value } }
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Filter chain. Order: header rewrite, then middleware(s), then a
|
|
140
|
+
# terminal redirect (which needs no backend).
|
|
141
|
+
def _filters(middleware:, redirect:, header_modifier:)
|
|
142
|
+
filters = []
|
|
143
|
+
|
|
144
|
+
if header_modifier
|
|
145
|
+
filters << { type: "RequestHeaderModifier", requestHeaderModifier: header_modifier }
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
Array(middleware).each do |name|
|
|
149
|
+
filters << {
|
|
150
|
+
type: "ExtensionRef",
|
|
151
|
+
extensionRef: { group: MIDDLEWARE_GROUP, kind: MIDDLEWARE_KIND, name: name },
|
|
152
|
+
}
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
if redirect
|
|
156
|
+
filters << { type: "RequestRedirect", requestRedirect: _redirect(redirect) }
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
filters
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# `redirect: true` is the common http->https 301. A hash customises
|
|
163
|
+
# scheme / status / path (ReplaceFullPath) / hostname.
|
|
164
|
+
def _redirect(redirect)
|
|
165
|
+
opts = redirect == true ? {} : redirect
|
|
166
|
+
|
|
167
|
+
rr = {
|
|
168
|
+
scheme: opts.fetch(:scheme, "https"),
|
|
169
|
+
statusCode: opts[:status] || opts[:statusCode] || 301,
|
|
170
|
+
}
|
|
171
|
+
rr[:path] = { type: "ReplaceFullPath", replaceFullPath: opts[:path] } if opts[:path]
|
|
172
|
+
rr[:hostname] = opts[:hostname] if opts[:hostname]
|
|
173
|
+
rr
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# backendRef in the convention's field order. The Service `namespace`
|
|
177
|
+
# is emitted only when the route lives in a different namespace than
|
|
178
|
+
# the backend (the cross-namespace model, which needs a ReferenceGrant
|
|
179
|
+
# the caller supplies). Omitting it yields the co-located short form.
|
|
180
|
+
def _backend(service)
|
|
181
|
+
ref = {}
|
|
182
|
+
# Cross-namespace backends carry the explicit group/kind/namespace
|
|
183
|
+
# (and need a ReferenceGrant); a co-located Service uses the bare
|
|
184
|
+
# short form. Emitting group/kind only in the former keeps both
|
|
185
|
+
# shapes byte-identical to the hand-written routes they replace.
|
|
186
|
+
if service[:namespace]
|
|
187
|
+
ref[:group] = ""
|
|
188
|
+
ref[:kind] = "Service"
|
|
189
|
+
ref[:name] = service.fetch(:name)
|
|
190
|
+
ref[:namespace] = service[:namespace]
|
|
191
|
+
else
|
|
192
|
+
ref[:name] = service.fetch(:name)
|
|
193
|
+
end
|
|
194
|
+
ref[:port] = service.fetch(:port)
|
|
195
|
+
ref[:weight] = service.fetch(:weight, 1)
|
|
196
|
+
ref
|
|
197
|
+
end
|
|
198
|
+
end
|
|
12
199
|
end
|
|
13
200
|
end
|
|
14
201
|
end
|
|
15
202
|
end
|
|
16
203
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
204
|
+
__END__
|
|
205
|
+
|
|
206
|
+
describe "GatewayApi::HTTPRoute" do
|
|
207
|
+
route = proc { |**kw| Kube::Cluster::Standard::GatewayApi::HTTPRoute.new(**kw) }
|
|
208
|
+
|
|
209
|
+
it "initializes without error" do
|
|
210
|
+
route.(
|
|
211
|
+
name: "docuseal",
|
|
212
|
+
gateway: "example-com-https",
|
|
213
|
+
domains: ["docuseal.example.com"],
|
|
214
|
+
prefix: ["/"],
|
|
215
|
+
service: { namespace: "ai", name: "docuseal", port: 3000 },
|
|
216
|
+
).to_yaml.is_a?(String).should == true
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
it "wires the fixed traefik-gateway parentRef with the given section" do
|
|
220
|
+
yaml = route.(
|
|
221
|
+
name: "docuseal",
|
|
222
|
+
gateway: "example-com-https",
|
|
223
|
+
domains: ["docuseal.example.com"],
|
|
224
|
+
prefix: ["/"],
|
|
225
|
+
service: { namespace: "ai", name: "docuseal", port: 3000 },
|
|
226
|
+
).to_yaml
|
|
227
|
+
|
|
228
|
+
yaml.should.include "traefik-gateway"
|
|
229
|
+
yaml.should.include "example-com-https"
|
|
230
|
+
yaml.should.include "docuseal.example.com"
|
|
231
|
+
yaml.should.include "PathPrefix"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
it "renders many typed matches onto one backend with timeouts" do
|
|
235
|
+
yaml = route.(
|
|
236
|
+
name: "forgejo-git",
|
|
237
|
+
gateway: "example-net-https",
|
|
238
|
+
domains: ["git.example.net"],
|
|
239
|
+
regex: ["/.+/info/refs", "/.+/git-upload-pack", "/.+/git-receive-pack"],
|
|
240
|
+
prefix: ["/api", "/v2"],
|
|
241
|
+
service: { namespace: "default", name: "forgejo-http", port: 3000 },
|
|
242
|
+
timeouts: { request: "600s", backendRequest: "600s" },
|
|
243
|
+
).to_yaml
|
|
244
|
+
|
|
245
|
+
yaml.should.include "RegularExpression"
|
|
246
|
+
yaml.should.include "git-upload-pack"
|
|
247
|
+
yaml.should.include "backendRequest: 600s"
|
|
248
|
+
# three regex matches share the single backend
|
|
249
|
+
yaml.scan(/RegularExpression/).length.should == 3
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it "renders a terminal https redirect with no backend" do
|
|
253
|
+
yaml = route.(
|
|
254
|
+
name: "sourcebot-http",
|
|
255
|
+
gateway: "example-com-http",
|
|
256
|
+
domains: ["sg.example.com"],
|
|
257
|
+
prefix: ["/"],
|
|
258
|
+
redirect: true,
|
|
259
|
+
).to_yaml
|
|
260
|
+
|
|
261
|
+
yaml.should.include "RequestRedirect"
|
|
262
|
+
yaml.should.include "statusCode: 301"
|
|
263
|
+
yaml.should.not.include "backendRefs"
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
it "renders a custom redirect with ReplaceFullPath and a 302" do
|
|
267
|
+
yaml = route.(
|
|
268
|
+
name: "forgejo-login",
|
|
269
|
+
gateway: "example-net-https",
|
|
270
|
+
domains: ["git.example.net"],
|
|
271
|
+
exact: ["/user/login"],
|
|
272
|
+
redirect: { path: "/user/oauth2/authelia", status: 302 },
|
|
273
|
+
).to_yaml
|
|
274
|
+
|
|
275
|
+
yaml.should.include "ReplaceFullPath"
|
|
276
|
+
yaml.should.include "statusCode: 302"
|
|
277
|
+
yaml.should.include "Exact"
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it "chains multiple middlewares as ExtensionRef filters" do
|
|
281
|
+
yaml = route.(
|
|
282
|
+
name: "docker-registry",
|
|
283
|
+
gateway: "example-net-https",
|
|
284
|
+
domains: ["registry.example.net"],
|
|
285
|
+
prefix: ["/"],
|
|
286
|
+
service: { namespace: "docker-registry", name: "docker-registry", port: 80 },
|
|
287
|
+
middleware: ["clear-site-data-cookies", "forwardauth-oauth2-proxy-example"],
|
|
288
|
+
).to_yaml
|
|
289
|
+
|
|
290
|
+
yaml.scan(/ExtensionRef/).length.should == 2
|
|
291
|
+
yaml.should.include "clear-site-data-cookies"
|
|
292
|
+
yaml.should.include "forwardauth-oauth2-proxy-example"
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
it "renders a header modifier and a co-located short-form backend" do
|
|
296
|
+
yaml = route.(
|
|
297
|
+
name: "sogo",
|
|
298
|
+
namespace: "mail",
|
|
299
|
+
gateway: "example-com-https",
|
|
300
|
+
domains: ["sogo.example.com"],
|
|
301
|
+
prefix: ["/"],
|
|
302
|
+
service: { name: "sogo", port: 80 },
|
|
303
|
+
header_modifier: { remove: ["x-webobjects-remote-user"] },
|
|
304
|
+
).to_yaml
|
|
305
|
+
|
|
306
|
+
yaml.should.include "RequestHeaderModifier"
|
|
307
|
+
yaml.should.include "x-webobjects-remote-user"
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
it "supports a websocket header match" do
|
|
311
|
+
yaml = route.(
|
|
312
|
+
name: "chrome-tool-ws",
|
|
313
|
+
gateway: "example-com-https",
|
|
314
|
+
domains: ["chrome-tool-ws.example.com"],
|
|
315
|
+
prefix: ["/"],
|
|
316
|
+
service: { namespace: "ai", name: "chrome-tool-ws", port: 8765 },
|
|
317
|
+
headers: { "Upgrade" => "websocket" },
|
|
318
|
+
).to_yaml
|
|
319
|
+
|
|
320
|
+
yaml.should.include "Upgrade"
|
|
321
|
+
yaml.should.include "websocket"
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
it "renders multiple hostnames on one route" do
|
|
325
|
+
yaml = route.(
|
|
326
|
+
name: "git",
|
|
327
|
+
gateway: "example-net-https",
|
|
328
|
+
domains: ["git.example.net", "git.example.com"],
|
|
329
|
+
prefix: ["/"],
|
|
330
|
+
service: { namespace: "default", name: "forgejo-http", port: 3000 },
|
|
331
|
+
).to_yaml
|
|
332
|
+
|
|
333
|
+
yaml.should.include "git.example.net"
|
|
334
|
+
yaml.should.include "git.example.com"
|
|
335
|
+
end
|
|
33
336
|
end
|
|
@@ -34,17 +34,17 @@ module Kube
|
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
37
|
+
__END__
|
|
38
|
+
|
|
39
|
+
describe "Job" do
|
|
40
|
+
it "initializes without error" do
|
|
41
|
+
Kube::Cluster::Standard::Job
|
|
42
|
+
.new(
|
|
43
|
+
name: "my-job",
|
|
44
|
+
image: "nixery.dev/cowsay", # nixery.dev is pretty sick, mate!
|
|
45
|
+
)
|
|
46
|
+
.to_yaml
|
|
47
|
+
.is_a?(String)
|
|
48
|
+
.should == true
|
|
49
49
|
end
|
|
50
50
|
end
|
|
@@ -51,17 +51,17 @@ module Kube
|
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
describe "JobWithServiceAccount" do
|
|
56
|
-
it "emits the RBAC trio plus the job" do
|
|
57
|
-
m = Kube::Cluster::Standard::JobWithServiceAccount.new(
|
|
58
|
-
name: "seed",
|
|
59
|
-
image: "nixery.dev/shell/kubectl",
|
|
60
|
-
rules: ["batch/jobs" => %w[create]],
|
|
61
|
-
command: ["true"],
|
|
62
|
-
)
|
|
54
|
+
__END__
|
|
63
55
|
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
describe "JobWithServiceAccount" do
|
|
57
|
+
it "emits the RBAC trio plus the job" do
|
|
58
|
+
m = Kube::Cluster::Standard::JobWithServiceAccount.new(
|
|
59
|
+
name: "seed",
|
|
60
|
+
image: "nixery.dev/shell/kubectl",
|
|
61
|
+
rules: ["batch/jobs" => %w[create]],
|
|
62
|
+
command: ["true"],
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
m.map { |r| r.to_h[:kind] }.sort.should == %w[Job Role RoleBinding ServiceAccount]
|
|
66
66
|
end
|
|
67
67
|
end
|
|
@@ -21,16 +21,16 @@ module Kube
|
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
__END__
|
|
25
|
+
|
|
26
|
+
describe "KubeVirt::VirtualMachine" do
|
|
27
|
+
it "initializes without error" do
|
|
28
|
+
Kube::Cluster::Standard::KubeVirt::VirtualMachine
|
|
29
|
+
.new(
|
|
30
|
+
name: "my-virtual-machine"
|
|
31
|
+
)
|
|
32
|
+
.to_yaml
|
|
33
|
+
.is_a?(String)
|
|
34
|
+
.should == true
|
|
35
35
|
end
|
|
36
36
|
end
|
|
@@ -59,18 +59,18 @@ module Kube
|
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
62
|
+
__END__
|
|
63
|
+
|
|
64
|
+
describe "MetaController::CompositeController" do
|
|
65
|
+
it "initializes without error" do
|
|
66
|
+
Kube::Cluster::Standard::MetaController::CompositeController
|
|
67
|
+
.new(
|
|
68
|
+
name: "my-controller",
|
|
69
|
+
webhook_url: "http://hook.default.svc/sync",
|
|
70
|
+
parent_resource: { apiVersion: "apps/v1", resource: "deployments" },
|
|
71
|
+
)
|
|
72
|
+
.to_yaml
|
|
73
|
+
.is_a?(String)
|
|
74
|
+
.should == true
|
|
75
75
|
end
|
|
76
76
|
end
|
|
@@ -58,18 +58,18 @@ module Kube
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
61
|
+
__END__
|
|
62
|
+
|
|
63
|
+
describe "MetaController::DecoratorController" do
|
|
64
|
+
it "initializes without error" do
|
|
65
|
+
Kube::Cluster::Standard::MetaController::DecoratorController
|
|
66
|
+
.new(
|
|
67
|
+
name: "my-controller",
|
|
68
|
+
webhook_url: "http://hook.default.svc/sync",
|
|
69
|
+
resources: { { apiVersion: "v1", resource: "pods" } => {} },
|
|
70
|
+
)
|
|
71
|
+
.to_yaml
|
|
72
|
+
.is_a?(String)
|
|
73
|
+
.should == true
|
|
74
74
|
end
|
|
75
75
|
end
|
|
@@ -32,14 +32,14 @@ module Kube
|
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
__END__
|
|
36
|
+
|
|
37
|
+
describe "Perses::Perses" do
|
|
38
|
+
it "initializes without error" do
|
|
39
|
+
Kube::Cluster::Standard::Perses::Perses
|
|
40
|
+
.new(name: "perses", image: "persesdev/perses:latest")
|
|
41
|
+
.to_yaml
|
|
42
|
+
.is_a?(String)
|
|
43
|
+
.should == true
|
|
44
44
|
end
|
|
45
45
|
end
|
|
@@ -34,18 +34,18 @@ module Kube
|
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
37
|
+
__END__
|
|
38
|
+
|
|
39
|
+
describe "Perses::PersesDatasource" do
|
|
40
|
+
it "initializes without error" do
|
|
41
|
+
Kube::Cluster::Standard::Perses::PersesDatasource
|
|
42
|
+
.new(
|
|
43
|
+
name: "victoriametrics",
|
|
44
|
+
plugin_kind: "PrometheusDatasource",
|
|
45
|
+
url: "http://vmsingle-vmsingle.metrics.svc:8429",
|
|
46
|
+
)
|
|
47
|
+
.to_yaml
|
|
48
|
+
.is_a?(String)
|
|
49
|
+
.should == true
|
|
50
50
|
end
|
|
51
51
|
end
|
|
@@ -21,17 +21,17 @@ module Kube
|
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
__END__
|
|
25
|
+
|
|
26
|
+
describe "PersistentVolumeClaim" do
|
|
27
|
+
it "initializes without error" do
|
|
28
|
+
Kube::Cluster::Standard::PersistentVolumeClaim
|
|
29
|
+
.new(
|
|
30
|
+
name: "my-volume",
|
|
31
|
+
storage: "25Gi",
|
|
32
|
+
)
|
|
33
|
+
.to_yaml
|
|
34
|
+
.is_a?(String)
|
|
35
|
+
.should == true
|
|
36
36
|
end
|
|
37
37
|
end
|
|
@@ -49,18 +49,18 @@ module Kube
|
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
describe "Role" do
|
|
54
|
-
it "expands the rules shorthand" do
|
|
55
|
-
yaml = Kube::Cluster::Standard::Role
|
|
56
|
-
.new(name: "r", rules: [
|
|
57
|
-
"secrets" => %w[get list],
|
|
58
|
-
"batch/cronjobs" => %w[get],
|
|
59
|
-
])
|
|
60
|
-
.to_yaml
|
|
52
|
+
__END__
|
|
61
53
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
54
|
+
describe "Role" do
|
|
55
|
+
it "expands the rules shorthand" do
|
|
56
|
+
yaml = Kube::Cluster::Standard::Role
|
|
57
|
+
.new(name: "r", rules: [
|
|
58
|
+
"secrets" => %w[get list],
|
|
59
|
+
"batch/cronjobs" => %w[get],
|
|
60
|
+
])
|
|
61
|
+
.to_yaml
|
|
62
|
+
|
|
63
|
+
yaml.include?("resources").should == true
|
|
64
|
+
yaml.include?("batch").should == true
|
|
65
65
|
end
|
|
66
66
|
end
|
|
@@ -38,16 +38,16 @@ module Kube
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
describe "RoleBinding" do
|
|
43
|
-
it "references the role and service account" do
|
|
44
|
-
yaml = Kube::Cluster::Standard::RoleBinding.new(
|
|
45
|
-
role: Kube::Cluster::Standard::Role.new(name: "r", rules: ["secrets" => %w[get]]),
|
|
46
|
-
service_account: Kube::Cluster::Standard::ServiceAccount.new(name: "sa"),
|
|
47
|
-
).to_yaml
|
|
41
|
+
__END__
|
|
48
42
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
describe "RoleBinding" do
|
|
44
|
+
it "references the role and service account" do
|
|
45
|
+
yaml = Kube::Cluster::Standard::RoleBinding.new(
|
|
46
|
+
role: Kube::Cluster::Standard::Role.new(name: "r", rules: ["secrets" => %w[get]]),
|
|
47
|
+
service_account: Kube::Cluster::Standard::ServiceAccount.new(name: "sa"),
|
|
48
|
+
).to_yaml
|
|
49
|
+
|
|
50
|
+
yaml.include?("name: r").should == true
|
|
51
|
+
yaml.include?("name: sa").should == true
|
|
52
52
|
end
|
|
53
53
|
end
|