kube_cluster 0.15.0 → 0.17.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/Gemfile.lock +1 -1
- data/lib/kube/cluster/middleware/set_namespace.rb +18 -2
- data/lib/kube/cluster/standard/cron_job_with_service_account.rb +71 -0
- data/lib/kube/cluster/standard/job_with_service_account.rb +67 -0
- data/lib/kube/cluster/standard/role.rb +66 -0
- data/lib/kube/cluster/standard/role_binding.rb +53 -0
- data/lib/kube/cluster/standard/service_account.rb +40 -0
- data/lib/kube/cluster/standard/service_account_with_role.rb +55 -0
- data/lib/kube/cluster/version.rb +1 -1
- metadata +7 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f7b1fa07c1c7e080961d17a281c4b2c8a6e84abc6cc9d4ae6c568415b2e989ae
|
|
4
|
+
data.tar.gz: 80994ba308efe68700f925dff182abf89908a55b1d35224c75eb577d7a42485c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ac7da1390a3fedf1973a709b0ce5547ee99590d68dfdf46686d4fcf64e237b3a37e86f27b3dfc1350ef22bd264828d4c13705b79e05e6abc1f5ac20ae2cd8364
|
|
7
|
+
data.tar.gz: 96154be98c24b04e56a49c2c6a4df93b94fe67bfa8b79c754c62e543187a7083418815049e05a47db516b16d58db91e2e9dc649a46f9d04243219c28af87df27
|
data/Gemfile.lock
CHANGED
|
@@ -25,9 +25,25 @@ module Kube
|
|
|
25
25
|
|
|
26
26
|
h = resource.to_h
|
|
27
27
|
h[:metadata] ||= {}
|
|
28
|
-
next resource if h[:metadata][:namespace] && h[:metadata][:namespace] != 'default'
|
|
29
28
|
|
|
30
|
-
h[:metadata][:namespace]
|
|
29
|
+
unless h[:metadata][:namespace] && h[:metadata][:namespace] != 'default'
|
|
30
|
+
h[:metadata][:namespace] = @namespace
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# A RoleBinding's ServiceAccount subjects need an explicit
|
|
34
|
+
# namespace; fill in any left blank with the target namespace so
|
|
35
|
+
# same-namespace bindings (e.g. ServiceAccountWithRole) resolve.
|
|
36
|
+
if h[:kind] == 'RoleBinding' && h[:subjects].is_a?(Array)
|
|
37
|
+
h[:subjects] = h[:subjects].map { |subject|
|
|
38
|
+
if subject[:kind] == 'ServiceAccount' &&
|
|
39
|
+
(subject[:namespace].nil? || subject[:namespace].to_s.empty?)
|
|
40
|
+
subject.merge(namespace: @namespace)
|
|
41
|
+
else
|
|
42
|
+
subject
|
|
43
|
+
end
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
|
|
31
47
|
resource.rebuild(h)
|
|
32
48
|
}
|
|
33
49
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "kube/cluster"
|
|
5
|
+
|
|
6
|
+
module Kube
|
|
7
|
+
module Cluster
|
|
8
|
+
module Standard
|
|
9
|
+
# A CronJob plus the ServiceAccount/Role/RoleBinding it runs as, bundled
|
|
10
|
+
# into one Manifest. The RBAC rules use the Role shorthand; the CronJob's
|
|
11
|
+
# serviceAccountName is wired to the generated ServiceAccount. Everything
|
|
12
|
+
# is named after +name+.
|
|
13
|
+
#
|
|
14
|
+
# CronJobWithServiceAccount.new(
|
|
15
|
+
# name: "glauth-config-builder",
|
|
16
|
+
# image: "nixery.dev/shell/ruby/kubectl/cacert",
|
|
17
|
+
# schedule: "*/5 * * * *",
|
|
18
|
+
# rules: [
|
|
19
|
+
# "secrets" => %w[get list],
|
|
20
|
+
# "batch/jobs" => %w[create],
|
|
21
|
+
# ],
|
|
22
|
+
# command: RubyScript(<<~'BUILD'),
|
|
23
|
+
# ...
|
|
24
|
+
# BUILD
|
|
25
|
+
# )
|
|
26
|
+
#
|
|
27
|
+
class CronJobWithServiceAccount < Kube::Cluster::Manifest
|
|
28
|
+
def initialize(name:, image:, schedule:, rules:, env: {}, command: nil,
|
|
29
|
+
backoff_limit: 3, ttl: 300, concurrency_policy: "Forbid", &block)
|
|
30
|
+
service_account_with_role = Kube::Cluster::Standard::ServiceAccountWithRole.new(
|
|
31
|
+
service_account: Kube::Cluster::Standard::ServiceAccount.new(name: name),
|
|
32
|
+
role: Kube::Cluster::Standard::Role.new(rules: rules),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
cron_job = Kube::Cluster::Standard::CronJob.new(
|
|
36
|
+
name: name,
|
|
37
|
+
image: image,
|
|
38
|
+
schedule: schedule,
|
|
39
|
+
env: env,
|
|
40
|
+
command: command,
|
|
41
|
+
backoff_limit: backoff_limit,
|
|
42
|
+
ttl: ttl,
|
|
43
|
+
concurrency_policy: concurrency_policy,
|
|
44
|
+
) do
|
|
45
|
+
spec.jobTemplate.spec.template.spec.serviceAccountName = name
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
super(*service_account_with_role.to_a, cron_job)
|
|
49
|
+
|
|
50
|
+
instance_exec(&block) if block
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
test do
|
|
58
|
+
describe "CronJobWithServiceAccount" do
|
|
59
|
+
it "emits the RBAC trio plus the cron job" do
|
|
60
|
+
m = Kube::Cluster::Standard::CronJobWithServiceAccount.new(
|
|
61
|
+
name: "builder",
|
|
62
|
+
image: "nixery.dev/shell/kubectl",
|
|
63
|
+
schedule: "*/5 * * * *",
|
|
64
|
+
rules: ["secrets" => %w[get list]],
|
|
65
|
+
command: ["true"],
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
m.map { |r| r.to_h[:kind] }.sort.should == %w[CronJob Role RoleBinding ServiceAccount]
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "kube/cluster"
|
|
5
|
+
|
|
6
|
+
module Kube
|
|
7
|
+
module Cluster
|
|
8
|
+
module Standard
|
|
9
|
+
# A one-shot Job plus the ServiceAccount/Role/RoleBinding it runs as,
|
|
10
|
+
# bundled into one Manifest. The RBAC rules use the Role shorthand; the
|
|
11
|
+
# Job's serviceAccountName is wired to the generated ServiceAccount.
|
|
12
|
+
# Everything is named after +name+.
|
|
13
|
+
#
|
|
14
|
+
# JobWithServiceAccount.new(
|
|
15
|
+
# name: "glauth-config-seed",
|
|
16
|
+
# image: "nixery.dev/shell/kubectl",
|
|
17
|
+
# rules: [
|
|
18
|
+
# "batch/cronjobs" => %w[get],
|
|
19
|
+
# "batch/jobs" => %w[create],
|
|
20
|
+
# ],
|
|
21
|
+
# command: BashScript(<<~'SEED'),
|
|
22
|
+
# ...
|
|
23
|
+
# SEED
|
|
24
|
+
# )
|
|
25
|
+
#
|
|
26
|
+
class JobWithServiceAccount < Kube::Cluster::Manifest
|
|
27
|
+
def initialize(name:, image:, rules:, env: {}, command: nil,
|
|
28
|
+
backoff_limit: 3, ttl: 300, &block)
|
|
29
|
+
service_account_with_role = Kube::Cluster::Standard::ServiceAccountWithRole.new(
|
|
30
|
+
service_account: Kube::Cluster::Standard::ServiceAccount.new(name: name),
|
|
31
|
+
role: Kube::Cluster::Standard::Role.new(rules: rules),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
job = Kube::Cluster::Standard::Job.new(
|
|
35
|
+
name: name,
|
|
36
|
+
image: image,
|
|
37
|
+
env: env,
|
|
38
|
+
command: command,
|
|
39
|
+
backoff_limit: backoff_limit,
|
|
40
|
+
ttl: ttl,
|
|
41
|
+
) do
|
|
42
|
+
spec.template.spec.serviceAccountName = name
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
super(*service_account_with_role.to_a, job)
|
|
46
|
+
|
|
47
|
+
instance_exec(&block) if block
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
test do
|
|
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
|
+
)
|
|
63
|
+
|
|
64
|
+
m.map { |r| r.to_h[:kind] }.sort.should == %w[Job Role RoleBinding ServiceAccount]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "kube/cluster"
|
|
5
|
+
|
|
6
|
+
module Kube
|
|
7
|
+
module Cluster
|
|
8
|
+
module Standard
|
|
9
|
+
# A Role with an ergonomic rules shorthand. Each rule maps a resource
|
|
10
|
+
# spec to its verbs; the spec is "resource" (core API group) or
|
|
11
|
+
# "group/resource":
|
|
12
|
+
#
|
|
13
|
+
# Role.new(rules: [
|
|
14
|
+
# "secrets" => %w[get list],
|
|
15
|
+
# "batch/cronjobs" => %w[get],
|
|
16
|
+
# ])
|
|
17
|
+
#
|
|
18
|
+
class Role < Kube::Cluster["Role"]
|
|
19
|
+
# The original rules shorthand, so a named copy can be rebuilt from it
|
|
20
|
+
# (rebuild downgrades the class; reconstructing keeps it a Standard::Role).
|
|
21
|
+
attr_reader :rules_input
|
|
22
|
+
|
|
23
|
+
def initialize(rules:, name: nil, &block)
|
|
24
|
+
@rules_input = rules
|
|
25
|
+
|
|
26
|
+
super() do
|
|
27
|
+
metadata.name = name if name
|
|
28
|
+
self.rules = Role.build_rules(rules)
|
|
29
|
+
instance_exec(&block) if block
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def name
|
|
34
|
+
to_h.dig(:metadata, :name)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.build_rules(rules)
|
|
38
|
+
entries = rules.is_a?(Hash) ? [rules] : Array(rules)
|
|
39
|
+
|
|
40
|
+
entries.flat_map do |entry|
|
|
41
|
+
entry.map do |spec, verbs|
|
|
42
|
+
group, resource = spec.include?("/") ? spec.split("/", 2) : ["", spec]
|
|
43
|
+
{ apiGroups: [group], resources: [resource], verbs: Array(verbs) }
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
test do
|
|
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
|
|
61
|
+
|
|
62
|
+
yaml.include?("resources").should == true
|
|
63
|
+
yaml.include?("batch").should == true
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "kube/cluster"
|
|
5
|
+
|
|
6
|
+
module Kube
|
|
7
|
+
module Cluster
|
|
8
|
+
module Standard
|
|
9
|
+
# A RoleBinding that wires a Role to a ServiceAccount. This is just the
|
|
10
|
+
# binding resource -- the Role and ServiceAccount are defined separately
|
|
11
|
+
# (and emitted together by ServiceAccountWithRole):
|
|
12
|
+
#
|
|
13
|
+
# RoleBinding.new(role: MyRole, service_account: MyServiceAccount)
|
|
14
|
+
#
|
|
15
|
+
# The subject namespace is left blank when the ServiceAccount has none, so
|
|
16
|
+
# the SetNamespace middleware fills it with the target namespace.
|
|
17
|
+
class RoleBinding < Kube::Cluster["RoleBinding"]
|
|
18
|
+
def initialize(role:, service_account:, name: nil, &block)
|
|
19
|
+
name ||= role.name || service_account.name
|
|
20
|
+
role_name = role.name || name
|
|
21
|
+
|
|
22
|
+
subject = { kind: "ServiceAccount", name: service_account.name }
|
|
23
|
+
subject[:namespace] = service_account.namespace if service_account.namespace
|
|
24
|
+
|
|
25
|
+
super() do
|
|
26
|
+
metadata.name = name
|
|
27
|
+
self.roleRef = {
|
|
28
|
+
apiGroup: "rbac.authorization.k8s.io",
|
|
29
|
+
kind: "Role",
|
|
30
|
+
name: role_name,
|
|
31
|
+
}
|
|
32
|
+
self.subjects = [subject]
|
|
33
|
+
instance_exec(&block) if block
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
test do
|
|
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
|
|
48
|
+
|
|
49
|
+
yaml.include?("name: r").should == true
|
|
50
|
+
yaml.include?("name: sa").should == true
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "kube/cluster"
|
|
5
|
+
|
|
6
|
+
module Kube
|
|
7
|
+
module Cluster
|
|
8
|
+
module Standard
|
|
9
|
+
class ServiceAccount < Kube::Cluster["ServiceAccount"]
|
|
10
|
+
def initialize(name:, namespace: nil, &block)
|
|
11
|
+
super() do
|
|
12
|
+
metadata.name = name
|
|
13
|
+
metadata.namespace = namespace if namespace
|
|
14
|
+
instance_exec(&block) if block
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def name
|
|
19
|
+
to_h.dig(:metadata, :name)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def namespace
|
|
23
|
+
to_h.dig(:metadata, :namespace)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
test do
|
|
31
|
+
describe "ServiceAccount" do
|
|
32
|
+
it "initializes without error" do
|
|
33
|
+
Kube::Cluster::Standard::ServiceAccount
|
|
34
|
+
.new(name: "my-sa")
|
|
35
|
+
.to_yaml
|
|
36
|
+
.is_a?(String)
|
|
37
|
+
.should == true
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "kube/cluster"
|
|
5
|
+
|
|
6
|
+
module Kube
|
|
7
|
+
module Cluster
|
|
8
|
+
module Standard
|
|
9
|
+
# Bundles a ServiceAccount, a Role, and the RoleBinding that ties them
|
|
10
|
+
# together into one Manifest. The Role and RoleBinding take the
|
|
11
|
+
# ServiceAccount's name unless a name is given explicitly:
|
|
12
|
+
#
|
|
13
|
+
# ServiceAccountWithRole.new(
|
|
14
|
+
# service_account: ServiceAccount.new(name: "glauth-config-builder"),
|
|
15
|
+
# role: Role.new(rules: [
|
|
16
|
+
# "secrets" => %w[get list],
|
|
17
|
+
# "batch/cronjobs" => %w[get],
|
|
18
|
+
# ]),
|
|
19
|
+
# )
|
|
20
|
+
#
|
|
21
|
+
class ServiceAccountWithRole < Kube::Cluster::Manifest
|
|
22
|
+
def initialize(service_account:, role:, name: nil, &block)
|
|
23
|
+
name ||= service_account.name
|
|
24
|
+
|
|
25
|
+
# Rebuild the Role with the derived name (a Standard::Role, so the
|
|
26
|
+
# binding's role.name reader works).
|
|
27
|
+
named_role = Kube::Cluster::Standard::Role.new(name: name, rules: role.rules_input)
|
|
28
|
+
|
|
29
|
+
role_binding = Kube::Cluster::Standard::RoleBinding.new(
|
|
30
|
+
role: named_role,
|
|
31
|
+
service_account: service_account,
|
|
32
|
+
name: name,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
super(service_account, named_role, role_binding)
|
|
36
|
+
|
|
37
|
+
instance_exec(&block) if block
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
test do
|
|
45
|
+
describe "ServiceAccountWithRole" do
|
|
46
|
+
it "emits the service account, role, and binding" do
|
|
47
|
+
m = Kube::Cluster::Standard::ServiceAccountWithRole.new(
|
|
48
|
+
service_account: Kube::Cluster::Standard::ServiceAccount.new(name: "sa"),
|
|
49
|
+
role: Kube::Cluster::Standard::Role.new(rules: ["secrets" => %w[get list]]),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
m.map { |r| r.to_h[:kind] }.sort.should == %w[Role RoleBinding ServiceAccount]
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
data/lib/kube/cluster/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kube_cluster
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.17.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nathan K
|
|
@@ -218,6 +218,7 @@ files:
|
|
|
218
218
|
- lib/kube/cluster/standard/cloud_native_pg/helm.rb
|
|
219
219
|
- lib/kube/cluster/standard/config_map.rb
|
|
220
220
|
- lib/kube/cluster/standard/cron_job.rb
|
|
221
|
+
- lib/kube/cluster/standard/cron_job_with_service_account.rb
|
|
221
222
|
- lib/kube/cluster/standard/custom_resource_definition.rb
|
|
222
223
|
- lib/kube/cluster/standard/daemon_set.rb
|
|
223
224
|
- lib/kube/cluster/standard/deployment_with_service.rb
|
|
@@ -226,14 +227,19 @@ files:
|
|
|
226
227
|
- lib/kube/cluster/standard/forgejo/helm.rb
|
|
227
228
|
- lib/kube/cluster/standard/gateway_api/http_route.rb
|
|
228
229
|
- lib/kube/cluster/standard/job.rb
|
|
230
|
+
- lib/kube/cluster/standard/job_with_service_account.rb
|
|
229
231
|
- lib/kube/cluster/standard/kube_virt/virtual_machine.rb
|
|
230
232
|
- lib/kube/cluster/standard/meta_controller/composite_controller.rb
|
|
231
233
|
- lib/kube/cluster/standard/meta_controller/decorator_controller.rb
|
|
232
234
|
- lib/kube/cluster/standard/perses/perses.rb
|
|
233
235
|
- lib/kube/cluster/standard/perses/perses_datasource.rb
|
|
234
236
|
- lib/kube/cluster/standard/persistent_volume_claim.rb
|
|
237
|
+
- lib/kube/cluster/standard/role.rb
|
|
238
|
+
- lib/kube/cluster/standard/role_binding.rb
|
|
235
239
|
- lib/kube/cluster/standard/secret.rb
|
|
236
240
|
- lib/kube/cluster/standard/service.rb
|
|
241
|
+
- lib/kube/cluster/standard/service_account.rb
|
|
242
|
+
- lib/kube/cluster/standard/service_account_with_role.rb
|
|
237
243
|
- lib/kube/cluster/standard/victoria_metrics/vl_agent.rb
|
|
238
244
|
- lib/kube/cluster/standard/victoria_metrics/vl_single.rb
|
|
239
245
|
- lib/kube/cluster/standard/victoria_metrics/vm_agent.rb
|