kube_cluster 1.3.0 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0768b58c75b80c58ddbe6bbae20aab3e57cad3a607058d7c2ebe64662d601f14'
4
- data.tar.gz: b6260994b93ce8c91c897d6e44fb771fb2df82eebab158353485a8423ba9a61a
3
+ metadata.gz: 161e8e4b158fcb49cbab16469213bb0a49fab8ff7d1669a1c974fa79b60e4d77
4
+ data.tar.gz: 87da0f1d7a75f18803146f1dc23bbe23bf5c188a3106751ef1ff95edfe38c9a5
5
5
  SHA512:
6
- metadata.gz: 0d10e0cda8c7483ca5190dc2351cf12a4a9ea856a61498cc1b210c1ff431d0e20c1fbe1908520f05c799329e1304d10ec1cdb0dcc7a80cd550ad8d0fc1ea695d
7
- data.tar.gz: ba7e0fcd06465f26a7d6197f41c4de71e713ebb06bde325433ac3dc41390ae7e95571e04cad35110f5cf4e17613262dae9189c8da3d35de4683b55537983ef7c
6
+ metadata.gz: d41568ed4346c1429eda172bb4021c38e72a1e4cb7994c8060991df077b6fb7eebc4a9f9c58689cf0839c97ad682d546aff7ab9360c57f8c14845d8626b07252
7
+ data.tar.gz: 85f8c1da91dcacfedf71b19736edef620113d71d211c51aa0f303cef72d63d2110cd8a4d9adab7f2fc2ee99f2fbec55837141c49f904587fbbd07d90e101325c
data/CHANGELOG.md CHANGED
@@ -5,6 +5,31 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.4.0] - 2026-07-13
9
+
10
+ ### Added
11
+ - `Standard::VictoriaMetrics::VMRule` — a wrapper for the VictoriaMetrics
12
+ operator's `VMRule` CRD (pinned to `operator.victoriametrics.com/v1beta1`).
13
+ Rules are built from `VMRule::Group` objects, each exposing `rule`/`alert`
14
+ helpers that construct `Rule`/`Alert` leaves; the rule expression is the
15
+ return value of a block, so multi-line PromQL reads as a heredoc.
16
+ - `Standard::VictoriaMetrics::VMAlert` — a wrapper for the VictoriaMetrics
17
+ operator's `VMAlert` CRD (pinned to `operator.victoriametrics.com/v1beta1`).
18
+ Wires `datasource`/`remoteWrite`/`remoteRead` and defaults `selectAllByDefault`
19
+ to true so it evaluates every `VMRule`; `notifier_url` is optional (recording
20
+ rules need no notifier).
21
+
22
+ ## [1.3.1] - 2026-07-13
23
+
24
+ ### Changed
25
+ - `Standard::CloudNativePg::Cluster` is now the bare named `Cluster` CR subclass
26
+ (resolved to `postgresql.cnpg.io/v1/Cluster`); the whole spec is supplied via
27
+ the block.
28
+
29
+ ### Removed
30
+ - `Standard::CloudNativePg::PostgresCluster` (shipped in 1.3.0) — it baked in a
31
+ specific deployment's config, which belongs at the call site, not the library.
32
+
8
33
  ## [1.3.0] - 2026-07-13
9
34
 
10
35
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kube_cluster (1.3.0)
4
+ kube_cluster (1.4.0)
5
5
  activesupport (~> 8.0)
6
6
  kube_kubectl (~> 2.0)
7
7
  kube_schema (~> 1.9.2)
@@ -7,16 +7,9 @@ module Kube
7
7
  module Cluster
8
8
  module Standard
9
9
  module CloudNativePg
10
- # A CloudNativePG Cluster CR. Thin wrapper: sets metadata, leaves the
11
- # (large, deployment-specific) spec to the block.
10
+ # A CloudNativePG Cluster CR, resolved to postgresql.cnpg.io/v1/Cluster.
11
+ # The (large, deployment-specific) spec is supplied via the block.
12
12
  class Cluster < Kube::Cluster["Cluster"]
13
- def initialize(name: "postgres", namespace: nil, &block)
14
- super() {
15
- metadata.name = name
16
- metadata.namespace = namespace if namespace
17
- instance_exec(&block) if block
18
- }
19
- end
20
13
  end
21
14
  end
22
15
  end
@@ -28,7 +21,8 @@ __END__
28
21
  describe "CloudNativePg::Cluster" do
29
22
  it "initializes without error" do
30
23
  Kube::Cluster::Standard::CloudNativePg::Cluster
31
- .new(name: "postgres", namespace: "cloudnative-pg") {
24
+ .new {
25
+ metadata.name = "postgres"
32
26
  spec.instances = 1
33
27
  spec.storage = { size: "1Gi" }
34
28
  }
@@ -0,0 +1,47 @@
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
+ module VictoriaMetrics
10
+ # Evaluates VMRule recording/alerting rules (selecting all by default).
11
+ # Recording-rule output is written back via remote_write_url; a notifier
12
+ # is only needed for alerting rules, so it is optional.
13
+ class VMAlert < Kube::Cluster["VMAlert"]
14
+ def initialize(name:, datasource_url:, remote_write_url:, remote_read_url: nil,
15
+ notifier_url: nil, evaluation_interval: nil, select_all: true, &block)
16
+ super() {
17
+ metadata.name = name
18
+ spec.selectAllByDefault = select_all
19
+ spec.datasource = { url: datasource_url }
20
+ spec.remoteWrite = { url: remote_write_url }
21
+ spec.remoteRead = { url: remote_read_url } if remote_read_url
22
+ spec.notifiers = [{ url: notifier_url }] if notifier_url
23
+ spec.evaluationInterval = evaluation_interval if evaluation_interval
24
+ instance_exec(&block) if block
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ __END__
34
+
35
+ describe "VictoriaMetrics::VMAlert" do
36
+ it "wires datasource and remote-write for recording rules" do
37
+ yaml = Kube::Cluster::Standard::VictoriaMetrics::VMAlert.new(
38
+ name: "vmalert",
39
+ datasource_url: "http://vmsingle-vmsingle.metrics.svc:8429/prometheus",
40
+ remote_write_url: "http://vmsingle-vmsingle.metrics.svc:8429/api/v1/write"
41
+ ).to_yaml
42
+
43
+ yaml.include?("operator.victoriametrics.com/v1beta1").should == true
44
+ yaml.include?("selectAllByDefault").should == true
45
+ yaml.include?("/api/v1/write").should == true
46
+ end
47
+ end
@@ -0,0 +1,138 @@
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
+ module VictoriaMetrics
10
+ # A recording rule. The block returns the PromQL expression, so
11
+ # multi-line queries read as a heredoc at the call site.
12
+ class Rule
13
+ def initialize(name, labels: nil, &block)
14
+ @name = name
15
+ @labels = labels
16
+ @expr = block.call.to_s if block
17
+ end
18
+
19
+ def to_h
20
+ h = { record: @name, expr: @expr }
21
+ h[:labels] = @labels if @labels
22
+ h
23
+ end
24
+ end
25
+
26
+ # An alerting rule. The block returns the PromQL expression.
27
+ class Alert
28
+ def initialize(name, for_: nil, keep_firing_for: nil, labels: nil, annotations: nil, &block)
29
+ @name = name
30
+ @for = for_
31
+ @keep_firing_for = keep_firing_for
32
+ @labels = labels
33
+ @annotations = annotations
34
+ @expr = block.call.to_s if block
35
+ end
36
+
37
+ def to_h
38
+ h = { alert: @name, expr: @expr }
39
+ h[:for] = @for if @for
40
+ h[:keep_firing_for] = @keep_firing_for if @keep_firing_for
41
+ h[:labels] = @labels if @labels
42
+ h[:annotations] = @annotations if @annotations
43
+ h
44
+ end
45
+ end
46
+
47
+ # A named group of rules. `rule`/`alert` build and collect the leaves;
48
+ # the block is instance_eval'd so those helpers read like keywords.
49
+ #
50
+ # Group.new("node.rules") {
51
+ # rule "node:node_num_cpu:sum" do
52
+ # <<~PROMQL
53
+ # count by (cluster, node) (...)
54
+ # PROMQL
55
+ # end
56
+ # }
57
+ class Group
58
+ def initialize(name, &block)
59
+ @name = name
60
+ @rules = []
61
+ instance_eval(&block) if block
62
+ end
63
+
64
+ def rule(name, **opts, &block) = @rules << Rule.new(name, **opts, &block)
65
+ def alert(name, **opts, &block) = @rules << Alert.new(name, **opts, &block)
66
+
67
+ def to_h = { name: @name, rules: @rules.map(&:to_h) }
68
+ end
69
+
70
+ # A VMRule CR: a set of rule Groups evaluated by VictoriaMetrics.
71
+ #
72
+ # VMRule.new(name: "node", groups: [
73
+ # Group.new("node.rules") { ... },
74
+ # ])
75
+ class VMRule < Kube::Cluster["VMRule"]
76
+ def initialize(name:, groups:, &block)
77
+ super() {
78
+ metadata.name = name
79
+ spec.groups = groups.map(&:to_h)
80
+ instance_exec(&block) if block
81
+ }
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ __END__
90
+
91
+ describe "VictoriaMetrics::VMRule" do
92
+ vmrule = Kube::Cluster::Standard::VictoriaMetrics::VMRule
93
+ group = Kube::Cluster::Standard::VictoriaMetrics::Group
94
+
95
+ it "emits a recording rule with the resolved v1beta1 apiVersion" do
96
+ yaml = vmrule.new(
97
+ name: "node",
98
+ groups: [
99
+ group.new("node.rules") {
100
+ rule "node:node_num_cpu:sum" do
101
+ "count by (cluster, node) (node_cpu_seconds_total)"
102
+ end
103
+ },
104
+ ]
105
+ ).to_yaml
106
+
107
+ yaml.include?("operator.victoriametrics.com/v1beta1").should == true
108
+ yaml.include?("record: node:node_num_cpu:sum").should == true
109
+ end
110
+
111
+ it "carries labels on records" do
112
+ group.new("g") {
113
+ rule "r", labels: { quantile: "0.99" } do
114
+ "histogram_quantile(0.99, x)"
115
+ end
116
+ }.to_h.should == {
117
+ name: "g",
118
+ rules: [{ record: "r", expr: "histogram_quantile(0.99, x)", labels: { quantile: "0.99" } }],
119
+ }
120
+ end
121
+
122
+ it "builds alerts with for/labels/annotations" do
123
+ group.new("g") {
124
+ alert "Down", for_: "5m", labels: { severity: "warning" }, annotations: { summary: "down" } do
125
+ "up == 0"
126
+ end
127
+ }.to_h.should == {
128
+ name: "g",
129
+ rules: [{
130
+ alert: "Down",
131
+ expr: "up == 0",
132
+ for: "5m",
133
+ labels: { severity: "warning" },
134
+ annotations: { summary: "down" },
135
+ }],
136
+ }
137
+ end
138
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Kube
4
4
  module Cluster
5
- VERSION = "1.3.0"
5
+ VERSION = "1.4.0"
6
6
  end
7
7
  end
data/lib/kube/cluster.rb CHANGED
@@ -128,7 +128,9 @@ Kube::Cluster.config do
128
128
  resolve "VLAgent", to: "operator.victoriametrics.com/v1/VLAgent"
129
129
  resolve "VLSingle", to: "operator.victoriametrics.com/v1/VLSingle"
130
130
  resolve "VMAgent", to: "operator.victoriametrics.com/v1beta1/VMAgent"
131
+ resolve "VMAlert", to: "operator.victoriametrics.com/v1beta1/VMAlert"
131
132
  resolve "VMNodeScrape", to: "operator.victoriametrics.com/v1beta1/VMNodeScrape"
133
+ resolve "VMRule", to: "operator.victoriametrics.com/v1beta1/VMRule"
132
134
  resolve "VMServiceScrape", to: "operator.victoriametrics.com/v1beta1/VMServiceScrape"
133
135
  resolve "VMSingle", to: "operator.victoriametrics.com/v1beta1/VMSingle"
134
136
 
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: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan K
@@ -219,7 +219,6 @@ files:
219
219
  - lib/kube/cluster/standard/cloud_native_pg/database_with_external_secret.rb
220
220
  - lib/kube/cluster/standard/cloud_native_pg/external_secret.rb
221
221
  - lib/kube/cluster/standard/cloud_native_pg/helm.rb
222
- - lib/kube/cluster/standard/cloud_native_pg/postgres_cluster.rb
223
222
  - lib/kube/cluster/standard/config_map.rb
224
223
  - lib/kube/cluster/standard/cron_job.rb
225
224
  - lib/kube/cluster/standard/cron_job_with_service_account.rb
@@ -247,7 +246,9 @@ files:
247
246
  - lib/kube/cluster/standard/victoria_metrics/vl_agent.rb
248
247
  - lib/kube/cluster/standard/victoria_metrics/vl_single.rb
249
248
  - lib/kube/cluster/standard/victoria_metrics/vm_agent.rb
249
+ - lib/kube/cluster/standard/victoria_metrics/vm_alert.rb
250
250
  - lib/kube/cluster/standard/victoria_metrics/vm_node_scrape.rb
251
+ - lib/kube/cluster/standard/victoria_metrics/vm_rule.rb
251
252
  - lib/kube/cluster/standard/victoria_metrics/vm_service_scrape.rb
252
253
  - lib/kube/cluster/standard/victoria_metrics/vm_single.rb
253
254
  - lib/kube/cluster/standard/volume_processing.rb
@@ -1,128 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/setup"
4
- require "kube/cluster"
5
- require "kube/cluster/standard/cloud_native_pg/cluster"
6
-
7
- module Kube
8
- module Cluster
9
- module Standard
10
- module CloudNativePg
11
- # The standard single-node PostgreSQL cluster: custom image, HA
12
- # replication slots, logical WAL, and barman-cloud WAL archiving.
13
- # Deployment-specific additions (managed roles, extra spec) come via the
14
- # block; databases are separate Database CRs.
15
- class PostgresCluster < Cluster
16
- def initialize(name: "postgres", namespace: nil, &block)
17
- super(name: name, namespace: namespace) {
18
- spec.affinity = { podAntiAffinityType: "preferred" }
19
- spec.bootstrap = {
20
- initdb: {
21
- database: "app",
22
- encoding: "UTF8",
23
- localeCType: "C",
24
- localeCollate: "C",
25
- owner: "app",
26
- },
27
- }
28
- spec.enablePDB = true
29
- spec.enableSuperuserAccess = false
30
- spec.failoverDelay = 0
31
- spec.imageName = "ghcr.io/general-intelligence-systems/postgresql:17-custom"
32
- spec.imagePullPolicy = "Always"
33
- spec.instances = 1
34
- spec.plugins = [{
35
- name: "barman-cloud.cloudnative-pg.io",
36
- isWALArchiver: true,
37
- parameters: { barmanObjectName: "cnpg-backups" },
38
- }]
39
- spec.logLevel = "info"
40
- spec.maxSyncReplicas = 0
41
- spec.minSyncReplicas = 0
42
- spec.monitoring = {
43
- disableDefaultQueries: false,
44
- enablePodMonitor: false,
45
- }
46
- spec.postgresGID = 26
47
- spec.postgresUID = 26
48
- spec.postgresql = {
49
- parameters: {
50
- archive_mode: "on",
51
- archive_timeout: "5min",
52
- dynamic_shared_memory_type: "posix",
53
- full_page_writes: "on",
54
- log_destination: "csvlog",
55
- log_directory: "/controller/log",
56
- log_filename: "postgres",
57
- log_rotation_age: "0",
58
- log_rotation_size: "0",
59
- log_truncate_on_rotation: "false",
60
- logging_collector: "on",
61
- max_parallel_workers: "32",
62
- max_replication_slots: "32",
63
- max_worker_processes: "32",
64
- shared_memory_type: "mmap",
65
- shared_preload_libraries: "",
66
- ssl_max_protocol_version: "TLSv1.3",
67
- ssl_min_protocol_version: "TLSv1.3",
68
- wal_keep_size: "512MB",
69
- wal_level: "logical",
70
- wal_log_hints: "on",
71
- wal_receiver_timeout: "5s",
72
- wal_sender_timeout: "5s",
73
- },
74
- syncReplicaElectionConstraint: {
75
- enabled: false,
76
- },
77
- }
78
- spec.primaryUpdateMethod = "restart"
79
- spec.primaryUpdateStrategy = "unsupervised"
80
- spec.probes = {
81
- liveness: {
82
- isolationCheck: {
83
- connectionTimeout: 1000,
84
- enabled: true,
85
- requestTimeout: 1000,
86
- },
87
- },
88
- }
89
- spec.replicationSlots = {
90
- highAvailability: {
91
- enabled: true,
92
- slotPrefix: "_cnpg_",
93
- },
94
- synchronizeReplicas: {
95
- enabled: true,
96
- },
97
- updateInterval: 30,
98
- }
99
- spec.resources = {}
100
- spec.smartShutdownTimeout = 180
101
- spec.startDelay = 3600
102
- spec.stopDelay = 1800
103
- spec.storage = {
104
- resizeInUseVolumes: true,
105
- size: "5Gi",
106
- }
107
- spec.switchoverDelay = 3600
108
-
109
- instance_exec(&block) if block
110
- }
111
- end
112
- end
113
- end
114
- end
115
- end
116
- end
117
-
118
- __END__
119
-
120
- describe "CloudNativePg::PostgresCluster" do
121
- it "initializes without error" do
122
- Kube::Cluster::Standard::CloudNativePg::PostgresCluster
123
- .new(namespace: "cloudnative-pg")
124
- .to_yaml
125
- .is_a?(String)
126
- .should == true
127
- end
128
- end