kube_cluster 0.20.1 → 0.21.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Gemfile.lock +5 -37
  4. data/flake.nix +2 -1
  5. data/kube_cluster.gemspec +1 -3
  6. data/lib/kube/cluster/container.rb +17 -17
  7. data/lib/kube/cluster/manifest.rb +158 -158
  8. data/lib/kube/cluster/middleware/annotations.rb +42 -42
  9. data/lib/kube/cluster/middleware/hpa_for_deployment.rb +134 -134
  10. data/lib/kube/cluster/middleware/ingress_for_service.rb +75 -75
  11. data/lib/kube/cluster/middleware/labels.rb +58 -58
  12. data/lib/kube/cluster/middleware/pod_anti_affinity.rb +104 -104
  13. data/lib/kube/cluster/middleware/resource_preset.rb +145 -145
  14. data/lib/kube/cluster/middleware/security_context.rb +127 -127
  15. data/lib/kube/cluster/middleware/service_for_deployment.rb +120 -120
  16. data/lib/kube/cluster/middleware.rb +219 -221
  17. data/lib/kube/cluster/resource/dirty_tracking.rb +388 -388
  18. data/lib/kube/cluster/resource.rb +16 -16
  19. data/lib/kube/cluster/standard/cdi/data_volume.rb +13 -13
  20. data/lib/kube/cluster/standard/cloud_native_pg/cluster.rb +11 -11
  21. data/lib/kube/cluster/standard/cloud_native_pg/database_with_external_secret.rb +11 -11
  22. data/lib/kube/cluster/standard/cloud_native_pg/external_secret.rb +11 -11
  23. data/lib/kube/cluster/standard/cloud_native_pg/helm.rb +26 -26
  24. data/lib/kube/cluster/standard/config_map.rb +11 -11
  25. data/lib/kube/cluster/standard/cron_job.rb +13 -13
  26. data/lib/kube/cluster/standard/cron_job_with_service_account.rb +12 -12
  27. data/lib/kube/cluster/standard/custom_resource_definition.rb +12 -12
  28. data/lib/kube/cluster/standard/daemon_set.rb +12 -12
  29. data/lib/kube/cluster/standard/deployment_with_service.rb +82 -82
  30. data/lib/kube/cluster/standard/env_processing.rb +15 -15
  31. data/lib/kube/cluster/standard/eso/external_secret.rb +13 -13
  32. data/lib/kube/cluster/standard/forgejo/helm.rb +11 -11
  33. data/lib/kube/cluster/standard/gateway_api/http_route.rb +302 -19
  34. data/lib/kube/cluster/standard/job.rb +12 -12
  35. data/lib/kube/cluster/standard/job_with_service_account.rb +11 -11
  36. data/lib/kube/cluster/standard/kube_virt/virtual_machine.rb +11 -11
  37. data/lib/kube/cluster/standard/meta_controller/composite_controller.rb +13 -13
  38. data/lib/kube/cluster/standard/meta_controller/decorator_controller.rb +13 -13
  39. data/lib/kube/cluster/standard/perses/perses.rb +9 -9
  40. data/lib/kube/cluster/standard/perses/perses_datasource.rb +13 -13
  41. data/lib/kube/cluster/standard/persistent_volume_claim.rb +12 -12
  42. data/lib/kube/cluster/standard/role.rb +12 -12
  43. data/lib/kube/cluster/standard/role_binding.rb +10 -10
  44. data/lib/kube/cluster/standard/secret.rb +11 -11
  45. data/lib/kube/cluster/standard/service.rb +12 -12
  46. data/lib/kube/cluster/standard/service_account.rb +9 -9
  47. data/lib/kube/cluster/standard/service_account_with_role.rb +10 -10
  48. data/lib/kube/cluster/standard/victoria_metrics/vl_agent.rb +9 -9
  49. data/lib/kube/cluster/standard/victoria_metrics/vl_single.rb +9 -9
  50. data/lib/kube/cluster/standard/victoria_metrics/vm_agent.rb +9 -9
  51. data/lib/kube/cluster/standard/victoria_metrics/vm_node_scrape.rb +9 -9
  52. data/lib/kube/cluster/standard/victoria_metrics/vm_service_scrape.rb +9 -9
  53. data/lib/kube/cluster/standard/victoria_metrics/vm_single.rb +9 -9
  54. data/lib/kube/cluster/standard/volume_processing.rb +3 -3
  55. data/lib/kube/cluster/version.rb +1 -1
  56. data/lib/kube/cluster.rb +0 -1
  57. data/lib/kube/helm/chart.rb +323 -323
  58. data/lib/kube/helm/endpoint.rb +58 -58
  59. data/lib/kube/helm/repo.rb +160 -160
  60. metadata +4 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9f57ee079352d4d49d3a72b968e7f8e896ff98fd520f55e32572db096e48873
4
- data.tar.gz: c30f1be092b7676bb653a289a1bd7f6616b7f6e6cc3f28037444adac0a800de5
3
+ metadata.gz: 8e702b334081767a62c208fcc0527bd69e531b1663c8f0073f5fd4cec5880263
4
+ data.tar.gz: fb4289693ab12e0a4ab9ed97d477d68440a5caae4a92f3ed6b8605daef59a430
5
5
  SHA512:
6
- metadata.gz: 5e66eb5cdb16c4023d56de2191ec5c0203471c7104ac4a689d84fa7be9dc80379d69914eb38c5928a560a7e63e3ce9992694da5ee6f96a6fbcf8ffeb89837f7e
7
- data.tar.gz: 1f6eed585979c1fb4e25b3812979e2ba11f1f6890ef9be94afd040e4723b990d7b4f65775a4befa98ff1362af24f231be4ce1910e2820b87307a906dd42575e1
6
+ metadata.gz: 614b806784409a283a0998004d19e5522b114a92d0b46798586f173eafd5718b88a66935f578a60406f6f779a4206c099d7bc8fee7f92429abad8c1facfbcaf1
7
+ data.tar.gz: b546741f901ee256ed2f603fa3ca76c348d2a728151e54a96a4206da81c710712684c541b8c65cd304b51c25ced7dbbb23578d697346b122ec9ce8f84047d3d1
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /kubeconfig.yaml
9
9
  *.swo
10
10
  *.swp
11
+ !flake.lock
data/Gemfile.lock CHANGED
@@ -1,11 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kube_cluster (0.18.0)
4
+ kube_cluster (0.20.0)
5
5
  activesupport (~> 8.0)
6
6
  kube_kubectl (~> 2.0)
7
- kube_schema (~> 1.7)
8
- scampi (~> 0.1)
7
+ kube_schema (~> 1.8)
9
8
 
10
9
  GEM
11
10
  remote: https://rubygems.org/
@@ -23,7 +22,6 @@ GEM
23
22
  securerandom (>= 0.3)
24
23
  tzinfo (~> 2.0, >= 2.0.5)
25
24
  uri (>= 0.13.1)
26
- ast (2.4.3)
27
25
  async (2.39.0)
28
26
  console (~> 1.29)
29
27
  fiber-annotation
@@ -77,9 +75,6 @@ GEM
77
75
  base64 (0.3.0)
78
76
  bigdecimal (4.1.2)
79
77
  build-files (1.10.2)
80
- colorize (1.1.0)
81
- colorize-extended (0.1.0)
82
- colorize (~> 1.1)
83
78
  concurrent-ruby (1.3.6)
84
79
  connection_pool (3.0.2)
85
80
  console (1.34.3)
@@ -137,11 +132,9 @@ GEM
137
132
  rubyshell (~> 1.5)
138
133
  shellwords (~> 0.2.2)
139
134
  string_builder (~> 1.2.2)
140
- kube_schema (1.7.0)
135
+ kube_schema (1.9.1)
141
136
  json_schemer (~> 2.5.0)
142
137
  rubyshell (~> 1.5.0)
143
- language_server-protocol (3.17.0.5)
144
- lint_roller (1.1.0)
145
138
  localhost (1.8.0)
146
139
  bake
147
140
  logger (1.7.0)
@@ -173,10 +166,6 @@ GEM
173
166
  net-smtp (0.5.1)
174
167
  net-protocol
175
168
  openssl (4.0.2)
176
- parallel (2.1.0)
177
- parser (3.3.11.1)
178
- ast (~> 2.4.1)
179
- racc
180
169
  pp (0.6.3)
181
170
  prettyprint
182
171
  prettyprint (0.2.0)
@@ -196,13 +185,11 @@ GEM
196
185
  psych (5.3.1)
197
186
  date
198
187
  stringio
199
- racc (1.8.1)
200
188
  rack (3.2.6)
201
189
  rackula (1.4.1)
202
190
  falcon (~> 0.46)
203
191
  samovar (~> 2.1)
204
192
  variant
205
- rainbow (3.1.1)
206
193
  rake (13.4.2)
207
194
  rbs (4.0.2)
208
195
  logger
@@ -215,28 +202,12 @@ GEM
215
202
  regexp_parser (2.12.0)
216
203
  reline (0.6.3)
217
204
  io-console (~> 0.5)
218
- rubocop (1.86.2)
219
- json (~> 2.3)
220
- language_server-protocol (~> 3.17.0.2)
221
- lint_roller (~> 1.1.0)
222
- parallel (>= 1.10)
223
- parser (>= 3.3.0.2)
224
- rainbow (>= 2.2.2, < 4.0)
225
- regexp_parser (>= 2.9.3, < 3.0)
226
- rubocop-ast (>= 1.49.0, < 2.0)
227
- ruby-progressbar (~> 1.7)
228
- unicode-display_width (>= 2.4.0, < 4.0)
229
- rubocop-ast (1.49.1)
230
- parser (>= 3.3.7.2)
231
- prism (~> 1.7)
232
- ruby-progressbar (1.13.0)
233
205
  rubyshell (1.5.0)
234
206
  rugged (1.9.0)
235
207
  samovar (2.4.1)
236
208
  console (~> 1.0)
237
209
  mapping (~> 1.0)
238
- scampi (0.1.7)
239
- colorize-extended
210
+ scampi (1.0.0)
240
211
  securerandom (0.4.1)
241
212
  shellwords (0.2.2)
242
213
  simpleidn (0.2.3)
@@ -249,9 +220,6 @@ GEM
249
220
  tsort (0.2.0)
250
221
  tzinfo (2.0.6)
251
222
  concurrent-ruby (~> 1.0)
252
- unicode-display_width (3.2.0)
253
- unicode-emoji (~> 4.1)
254
- unicode-emoji (4.2.0)
255
223
  uri (1.1.1)
256
224
  utopia (2.32.1)
257
225
  bake (~> 0.20)
@@ -290,7 +258,7 @@ DEPENDENCIES
290
258
  bake-releases
291
259
  kube_cluster!
292
260
  rake (~> 13.0)
293
- rubocop (~> 1.21)
261
+ scampi (~> 1.0)
294
262
  utopia-project
295
263
 
296
264
  BUNDLED WITH
data/flake.nix CHANGED
@@ -29,10 +29,11 @@
29
29
  ];
30
30
 
31
31
  shellHook = ''
32
- export GEM_HOME="$HOME/.gem"
32
+ export GEM_HOME="$HOME/.gem-${ruby.version}"
33
33
  export GEM_PATH="$GEM_HOME"
34
34
  export PATH="$GEM_HOME/bin:$PATH"
35
35
  export BUNDLE_PATH="$GEM_HOME"
36
+ export BUNDLE_GEMFILE="$PWD/Gemfile"
36
37
  export BUNDLE_BIN="$GEM_HOME/bin"
37
38
  export KUBECONFIG="$PWD/kubeconfig.yaml"
38
39
  '';
data/kube_cluster.gemspec CHANGED
@@ -28,10 +28,8 @@ Gem::Specification.new do |spec|
28
28
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
29
  spec.require_paths = ["lib"]
30
30
 
31
- spec.add_dependency "scampi", "~> 0.1"
32
-
33
31
  spec.add_development_dependency "rake", "~> 13.0"
34
- spec.add_development_dependency "rubocop", "~> 1.21"
32
+ spec.add_development_dependency "scampi", "~> 1.0"
35
33
 
36
34
  spec.add_dependency "kube_schema", "~> 1.9.1"
37
35
  spec.add_dependency "kube_kubectl", "~> 2.0"
@@ -10,24 +10,24 @@ module Kube
10
10
  end
11
11
  end
12
12
 
13
- test do
14
- it "creates a valid container" do
15
- c = Kube::Cluster::Container.new(name: "app", image: "nginx:1.27")
16
- c.valid?.should.be.true
17
- c.name.should == "app"
18
- end
13
+ __END__
14
+
15
+ it "creates a valid container" do
16
+ c = Kube::Cluster::Container.new(name: "app", image: "nginx:1.27")
17
+ c.valid?.should.be.true
18
+ c.name.should == "app"
19
+ end
19
20
 
20
- it "auto-coerces inside a Deployment" do
21
- c = Kube::Cluster::Container.new(name: "app", image: "nginx:1.27")
21
+ it "auto-coerces inside a Deployment" do
22
+ c = Kube::Cluster::Container.new(name: "app", image: "nginx:1.27")
22
23
 
23
- deploy = Kube::Cluster["Deployment"].new {
24
- metadata.name = "web"
25
- spec.replicas = 1
26
- spec.selector.matchLabels = { app: "web" }
27
- spec.template.metadata.labels = { app: "web" }
28
- spec.template.spec.containers = [c]
29
- }
24
+ deploy = Kube::Cluster["Deployment"].new {
25
+ metadata.name = "web"
26
+ spec.replicas = 1
27
+ spec.selector.matchLabels = { app: "web" }
28
+ spec.template.metadata.labels = { app: "web" }
29
+ spec.template.spec.containers = [c]
30
+ }
30
31
 
31
- deploy.to_h[:spec][:template][:spec][:containers].first[:name].should == "app"
32
- end
32
+ deploy.to_h[:spec][:template][:spec][:containers].first[:name].should == "app"
33
33
  end
@@ -52,204 +52,204 @@ module Kube
52
52
  end
53
53
  end
54
54
 
55
- test do
56
- Middleware = Kube::Cluster::Middleware
55
+ __END__
57
56
 
58
- # ── Bare manifest ────────────────────────────────────────────────────────
57
+ Middleware = Kube::Cluster::Middleware
59
58
 
60
- it "bare_manifest_enumerates_resources_unchanged" do
61
- m = Kube::Cluster::Manifest.new
62
- m << Kube::Cluster["ConfigMap"].new {
63
- metadata.name = "test"
64
- self.data = { key: "value" }
65
- }
59
+ # ── Bare manifest ────────────────────────────────────────────────────────
66
60
 
67
- resources = m.to_a
68
- resources.size.should == 1
69
- end
61
+ it "bare_manifest_enumerates_resources_unchanged" do
62
+ m = Kube::Cluster::Manifest.new
63
+ m << Kube::Cluster["ConfigMap"].new {
64
+ metadata.name = "test"
65
+ self.data = { key: "value" }
66
+ }
70
67
 
71
- # ── Stack transforms resources ───────────────────────────────────────────
68
+ resources = m.to_a
69
+ resources.size.should == 1
70
+ end
72
71
 
73
- it "stack_transforms_resources" do
74
- m = Kube::Cluster::Manifest.new
75
- m << Kube::Cluster["ConfigMap"].new {
76
- metadata.name = "test"
77
- }
72
+ # ── Stack transforms resources ───────────────────────────────────────────
78
73
 
79
- stack = Middleware::Stack.new do
80
- use Middleware::SetNamespace, "production"
81
- end
82
- stack.call(m)
74
+ it "stack_transforms_resources" do
75
+ m = Kube::Cluster::Manifest.new
76
+ m << Kube::Cluster["ConfigMap"].new {
77
+ metadata.name = "test"
78
+ }
83
79
 
84
- resources = m.to_a
85
- resources.first.to_h.dig(:metadata, :namespace).should == "production"
80
+ stack = Middleware::Stack.new do
81
+ use Middleware::SetNamespace, "production"
86
82
  end
83
+ stack.call(m)
87
84
 
88
- it "to_yaml_reflects_middleware" do
89
- m = Kube::Cluster::Manifest.new
90
- m << Kube::Cluster["ConfigMap"].new {
91
- metadata.name = "test"
92
- }
85
+ resources = m.to_a
86
+ resources.first.to_h.dig(:metadata, :namespace).should == "production"
87
+ end
93
88
 
94
- Middleware::SetNamespace.new("production").call(m)
89
+ it "to_yaml_reflects_middleware" do
90
+ m = Kube::Cluster::Manifest.new
91
+ m << Kube::Cluster["ConfigMap"].new {
92
+ metadata.name = "test"
93
+ }
95
94
 
96
- yaml = m.to_yaml
97
- yaml.should.include "namespace: production"
98
- end
95
+ Middleware::SetNamespace.new("production").call(m)
99
96
 
100
- it "enumerable_methods_work" do
101
- m = Kube::Cluster::Manifest.new
102
- m << Kube::Cluster["ConfigMap"].new { metadata.name = "a" }
103
- m << Kube::Cluster["ConfigMap"].new { metadata.name = "b" }
97
+ yaml = m.to_yaml
98
+ yaml.should.include "namespace: production"
99
+ end
104
100
 
105
- Middleware::SetNamespace.new("production").call(m)
101
+ it "enumerable_methods_work" do
102
+ m = Kube::Cluster::Manifest.new
103
+ m << Kube::Cluster["ConfigMap"].new { metadata.name = "a" }
104
+ m << Kube::Cluster["ConfigMap"].new { metadata.name = "b" }
106
105
 
107
- names = m.map { |r| r.to_h.dig(:metadata, :name) }
108
- names.should == %w[a b]
109
- end
106
+ Middleware::SetNamespace.new("production").call(m)
110
107
 
111
- # ── Multi-middleware stack ──────────────────────────────────────────────
108
+ names = m.map { |r| r.to_h.dig(:metadata, :name) }
109
+ names.should == %w[a b]
110
+ end
112
111
 
113
- it "multiple_middleware_compose_in_order" do
114
- m = Kube::Cluster::Manifest.new
115
- m << Kube::Cluster["ConfigMap"].new {
116
- metadata.name = "test"
117
- }
112
+ # ── Multi-middleware stack ──────────────────────────────────────────────
118
113
 
119
- stack = Middleware::Stack.new do
120
- use Middleware::SetNamespace, "staging"
121
- use Middleware::Labels, app: "myapp", managed_by: "kube_cluster"
122
- end
123
- stack.call(m)
114
+ it "multiple_middleware_compose_in_order" do
115
+ m = Kube::Cluster::Manifest.new
116
+ m << Kube::Cluster["ConfigMap"].new {
117
+ metadata.name = "test"
118
+ }
124
119
 
125
- r = m.first
126
- h = r.to_h
127
-
128
- h.dig(:metadata, :namespace).should == "staging"
120
+ stack = Middleware::Stack.new do
121
+ use Middleware::SetNamespace, "staging"
122
+ use Middleware::Labels, app: "myapp", managed_by: "kube_cluster"
129
123
  end
124
+ stack.call(m)
130
125
 
131
- # ── size reflects resource count ─────────────────────────────────────────
126
+ r = m.first
127
+ h = r.to_h
132
128
 
133
- it "size_reflects_resource_count" do
134
- m = Kube::Cluster::Manifest.new
135
- m << Kube::Cluster["ConfigMap"].new { metadata.name = "a" }
136
- m << Kube::Cluster["ConfigMap"].new { metadata.name = "b" }
129
+ h.dig(:metadata, :namespace).should == "staging"
130
+ end
137
131
 
138
- m.size.should == 2
139
- end
132
+ # ── size reflects resource count ─────────────────────────────────────────
140
133
 
141
- # ── each without block ──────────────────────────────────────────────────
134
+ it "size_reflects_resource_count" do
135
+ m = Kube::Cluster::Manifest.new
136
+ m << Kube::Cluster["ConfigMap"].new { metadata.name = "a" }
137
+ m << Kube::Cluster["ConfigMap"].new { metadata.name = "b" }
142
138
 
143
- it "each_without_block_returns_enumerator" do
144
- m = Kube::Cluster::Manifest.new
145
- m << Kube::Cluster["ConfigMap"].new { metadata.name = "test" }
139
+ m.size.should == 2
140
+ end
146
141
 
147
- Middleware::SetNamespace.new("production").call(m)
142
+ # ── each without block ──────────────────────────────────────────────────
148
143
 
149
- enum = m.each
150
- enum.should.be.instance_of Enumerator
151
- end
144
+ it "each_without_block_returns_enumerator" do
145
+ m = Kube::Cluster::Manifest.new
146
+ m << Kube::Cluster["ConfigMap"].new { metadata.name = "test" }
152
147
 
153
- # ── Generative middleware produces new resources ─────────────────────────
154
-
155
- it "generative_middleware_adds_service" do
156
- m = Kube::Cluster::Manifest.new
157
- m << Kube::Cluster["Deployment"].new {
158
- metadata.name = "web"
159
- metadata.namespace = "default"
160
- spec.selector.matchLabels = { app: "web" }
161
- spec.template.metadata.labels = { app: "web" }
162
- spec.template.spec.containers = [
163
- { name: "web", image: "nginx", ports: [{ name: "http", containerPort: 8080 }] },
164
- ]
165
- }
148
+ Middleware::SetNamespace.new("production").call(m)
166
149
 
167
- Middleware::ServiceForDeployment.new.call(m)
150
+ enum = m.each
151
+ enum.should.be.instance_of Enumerator
152
+ end
168
153
 
169
- kinds = m.map { |r| r.to_h[:kind] }
170
- kinds.should == %w[Deployment Service]
171
- end
154
+ # ── Generative middleware produces new resources ─────────────────────────
172
155
 
173
- it "generative_middleware_does_not_affect_non_matching_resources" do
174
- m = Kube::Cluster::Manifest.new
175
- m << Kube::Cluster["ConfigMap"].new {
176
- metadata.name = "config"
177
- }
156
+ it "generative_middleware_adds_service" do
157
+ m = Kube::Cluster::Manifest.new
158
+ m << Kube::Cluster["Deployment"].new {
159
+ metadata.name = "web"
160
+ metadata.namespace = "default"
161
+ spec.selector.matchLabels = { app: "web" }
162
+ spec.template.metadata.labels = { app: "web" }
163
+ spec.template.spec.containers = [
164
+ { name: "web", image: "nginx", ports: [{ name: "http", containerPort: 8080 }] },
165
+ ]
166
+ }
178
167
 
179
- Middleware::ServiceForDeployment.new.call(m)
180
-
181
- resources = m.to_a
182
- resources.size.should == 1
183
- end
168
+ Middleware::ServiceForDeployment.new.call(m)
184
169
 
185
- # ── Generated resources flow through subsequent middleware stages ────────
186
-
187
- it "generated_resources_flow_through_subsequent_stages" do
188
- m = Kube::Cluster::Manifest.new
189
- m << Kube::Cluster["Deployment"].new {
190
- metadata.name = "web"
191
- spec.selector.matchLabels = { app: "web" }
192
- spec.template.metadata.labels = { app: "web" }
193
- spec.template.spec.containers = [
194
- { name: "web", image: "nginx", ports: [{ name: "http", containerPort: 8080 }] },
195
- ]
196
- }
170
+ kinds = m.map { |r| r.to_h[:kind] }
171
+ kinds.should == %w[Deployment Service]
172
+ end
197
173
 
198
- stack = Middleware::Stack.new do
199
- use Middleware::ServiceForDeployment # generates Service
200
- use Middleware::SetNamespace, "production" # namespaces everything
201
- use Middleware::Labels, managed_by: "middleware" # labels everything
202
- end
203
- stack.call(m)
174
+ it "generative_middleware_does_not_affect_non_matching_resources" do
175
+ m = Kube::Cluster::Manifest.new
176
+ m << Kube::Cluster["ConfigMap"].new {
177
+ metadata.name = "config"
178
+ }
204
179
 
205
- resources = m.to_a
206
- resources.size.should == 2
207
- end
180
+ Middleware::ServiceForDeployment.new.call(m)
208
181
 
209
- # ── YAML serializes integers correctly ──────────────────────────────────
210
-
211
- it "to_yaml_serializes_integers_as_plain_values" do
212
- m = Kube::Cluster::Manifest.new
213
- m << Kube::Cluster["Deployment"].new {
214
- metadata.name = "web"
215
- spec.selector.matchLabels = { app: "web" }
216
- spec.template.metadata.labels = { app: "web" }
217
- spec.template.spec.containers = [
218
- { name: "web", image: "nginx", ports: [{ name: "http", containerPort: 8080 }] },
219
- ]
220
- }
182
+ resources = m.to_a
183
+ resources.size.should == 1
184
+ end
221
185
 
222
- yaml = m.to_yaml
223
- yaml.should.include "containerPort: 8080"
186
+ # ── Generated resources flow through subsequent middleware stages ────────
187
+
188
+ it "generated_resources_flow_through_subsequent_stages" do
189
+ m = Kube::Cluster::Manifest.new
190
+ m << Kube::Cluster["Deployment"].new {
191
+ metadata.name = "web"
192
+ spec.selector.matchLabels = { app: "web" }
193
+ spec.template.metadata.labels = { app: "web" }
194
+ spec.template.spec.containers = [
195
+ { name: "web", image: "nginx", ports: [{ name: "http", containerPort: 8080 }] },
196
+ ]
197
+ }
198
+
199
+ stack = Middleware::Stack.new do
200
+ use Middleware::ServiceForDeployment # generates Service
201
+ use Middleware::SetNamespace, "production" # namespaces everything
202
+ use Middleware::Labels, managed_by: "middleware" # labels everything
224
203
  end
204
+ stack.call(m)
225
205
 
226
- # ── Multi-generative: chained generation ────────────────────────────────
227
-
228
- it "chained_generative_middleware" do
229
- m = Kube::Cluster::Manifest.new
230
- m << Kube::Cluster["Deployment"].new {
231
- metadata.name = "web"
232
- metadata.namespace = "default"
233
- metadata.labels = {
234
- "app.kubernetes.io/expose": "app.example.com",
235
- "app.kubernetes.io/autoscale": "2-10",
236
- }
237
- spec.selector.matchLabels = { app: "web" }
238
- spec.template.metadata.labels = { app: "web" }
239
- spec.template.spec.containers = [
240
- { name: "web", image: "nginx", ports: [{ name: "http", containerPort: 8080 }] },
241
- ]
242
- }
206
+ resources = m.to_a
207
+ resources.size.should == 2
208
+ end
243
209
 
244
- stack = Middleware::Stack.new do
245
- use Middleware::ServiceForDeployment # Deployment → +Service
246
- use Middleware::IngressForService # Service with expose label → +Ingress
247
- use Middleware::HPAForDeployment # Deployment with autoscale label → +HPA
248
- end
249
- stack.call(m)
210
+ # ── YAML serializes integers correctly ──────────────────────────────────
211
+
212
+ it "to_yaml_serializes_integers_as_plain_values" do
213
+ m = Kube::Cluster::Manifest.new
214
+ m << Kube::Cluster["Deployment"].new {
215
+ metadata.name = "web"
216
+ spec.selector.matchLabels = { app: "web" }
217
+ spec.template.metadata.labels = { app: "web" }
218
+ spec.template.spec.containers = [
219
+ { name: "web", image: "nginx", ports: [{ name: "http", containerPort: 8080 }] },
220
+ ]
221
+ }
222
+
223
+ yaml = m.to_yaml
224
+ yaml.should.include "containerPort: 8080"
225
+ end
250
226
 
251
- kinds = m.map { |r| r.to_h[:kind] }
227
+ # ── Multi-generative: chained generation ────────────────────────────────
252
228
 
253
- m.to_a.size.should == 4
229
+ it "chained_generative_middleware" do
230
+ m = Kube::Cluster::Manifest.new
231
+ m << Kube::Cluster["Deployment"].new {
232
+ metadata.name = "web"
233
+ metadata.namespace = "default"
234
+ metadata.labels = {
235
+ "app.kubernetes.io/expose": "app.example.com",
236
+ "app.kubernetes.io/autoscale": "2-10",
237
+ }
238
+ spec.selector.matchLabels = { app: "web" }
239
+ spec.template.metadata.labels = { app: "web" }
240
+ spec.template.spec.containers = [
241
+ { name: "web", image: "nginx", ports: [{ name: "http", containerPort: 8080 }] },
242
+ ]
243
+ }
244
+
245
+ stack = Middleware::Stack.new do
246
+ use Middleware::ServiceForDeployment # Deployment → +Service
247
+ use Middleware::IngressForService # Service with expose label → +Ingress
248
+ use Middleware::HPAForDeployment # Deployment with autoscale label → +HPA
254
249
  end
250
+ stack.call(m)
251
+
252
+ kinds = m.map { |r| r.to_h[:kind] }
253
+
254
+ m.to_a.size.should == 4
255
255
  end