Skip to content

Commit 2d1c8aa

Browse files
kvapsclaude
andcommitted
feat(platform): add flux-plunger controller
Add flux-plunger controller to automatically fix HelmRelease resources with "has no deployed releases" error. The controller watches HelmRelease resources and performs the following: - Detects HelmRelease with "has no deployed releases" error - Suspends the HelmRelease with flux-client-side-apply field manager - Deletes the latest Helm release secret - Updates annotation with processed version to prevent recursive deletion - Unsuspends the HelmRelease to allow Flux to retry Special handling for suspended HelmRelease: - If suspend=true and latest+1==processed: removes suspend - Otherwise: skips processing as suspended by external process Co-Authored-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]>
1 parent bfd2e1f commit 2d1c8aa

12 files changed

Lines changed: 674 additions & 0 deletions

File tree

‎cmd/flux-plunger/main.go‎

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*
2+
Copyright 2025.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package main
18+
19+
import (
20+
"crypto/tls"
21+
"flag"
22+
"os"
23+
24+
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
25+
// to ensure that exec-entrypoint and run can make use of them.
26+
_ "k8s.io/client-go/plugin/pkg/client/auth"
27+
28+
helmv2 "github.com/fluxcd/helm-controller/api/v2"
29+
"k8s.io/apimachinery/pkg/runtime"
30+
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
31+
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
32+
ctrl "sigs.k8s.io/controller-runtime"
33+
"sigs.k8s.io/controller-runtime/pkg/healthz"
34+
"sigs.k8s.io/controller-runtime/pkg/log/zap"
35+
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
36+
37+
"github.com/cozystack/cozystack/internal/controller/fluxplunger"
38+
// +kubebuilder:scaffold:imports
39+
)
40+
41+
var (
42+
scheme = runtime.NewScheme()
43+
setupLog = ctrl.Log.WithName("setup")
44+
)
45+
46+
func init() {
47+
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
48+
utilruntime.Must(helmv2.AddToScheme(scheme))
49+
50+
// +kubebuilder:scaffold:scheme
51+
}
52+
53+
func main() {
54+
var metricsAddr string
55+
var enableLeaderElection bool
56+
var probeAddr string
57+
var secureMetrics bool
58+
var enableHTTP2 bool
59+
var tlsOpts []func(*tls.Config)
60+
61+
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
62+
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
63+
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
64+
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
65+
"Enable leader election for controller manager. "+
66+
"Enabling this will ensure there is only one active controller manager.")
67+
flag.BoolVar(&secureMetrics, "metrics-secure", true,
68+
"If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.")
69+
flag.BoolVar(&enableHTTP2, "enable-http2", false,
70+
"If set, HTTP/2 will be enabled for the metrics server")
71+
72+
opts := zap.Options{
73+
Development: false,
74+
}
75+
opts.BindFlags(flag.CommandLine)
76+
flag.Parse()
77+
78+
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
79+
80+
// if the enable-http2 flag is false (the default), http/2 should be disabled
81+
// due to its vulnerabilities. More specifically, disabling http/2 will
82+
// prevent from being vulnerable to the HTTP/2 Stream Cancellation and
83+
// Rapid Reset CVEs. For more information see:
84+
// - https://github.com/advisories/GHSA-qppj-fm5r-hxr3
85+
// - https://github.com/advisories/GHSA-4374-p667-p6c8
86+
disableHTTP2 := func(c *tls.Config) {
87+
setupLog.Info("disabling http/2")
88+
c.NextProtos = []string{"http/1.1"}
89+
}
90+
91+
if !enableHTTP2 {
92+
tlsOpts = append(tlsOpts, disableHTTP2)
93+
}
94+
95+
// Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server.
96+
// More info:
97+
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/metrics/server
98+
// - https://book.kubebuilder.io/reference/metrics.html
99+
metricsServerOptions := metricsserver.Options{
100+
BindAddress: metricsAddr,
101+
SecureServing: secureMetrics,
102+
TLSOpts: tlsOpts,
103+
}
104+
105+
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
106+
Scheme: scheme,
107+
Metrics: metricsServerOptions,
108+
HealthProbeBindAddress: probeAddr,
109+
LeaderElection: enableLeaderElection,
110+
LeaderElectionID: "flux-plunger.cozystack.io",
111+
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
112+
// when the Manager ends. This requires the binary to immediately end when the
113+
// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
114+
// speeds up voluntary leader transitions as the new leader don't have to wait
115+
// LeaseDuration time first.
116+
//
117+
// In the default scaffold provided, the program ends immediately after
118+
// the manager stops, so would be fine to enable this option. However,
119+
// if you are doing or is intended to do any operation such as perform cleanups
120+
// after the manager stops then its usage might be unsafe.
121+
// LeaderElectionReleaseOnCancel: true,
122+
})
123+
if err != nil {
124+
setupLog.Error(err, "unable to create manager")
125+
os.Exit(1)
126+
}
127+
128+
if err = (&fluxplunger.FluxPlunger{
129+
Client: mgr.GetClient(),
130+
}).SetupWithManager(mgr); err != nil {
131+
setupLog.Error(err, "unable to create controller", "controller", "FluxPlunger")
132+
os.Exit(1)
133+
}
134+
135+
// +kubebuilder:scaffold:builder
136+
137+
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
138+
setupLog.Error(err, "unable to set up health check")
139+
os.Exit(1)
140+
}
141+
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
142+
setupLog.Error(err, "unable to set up ready check")
143+
os.Exit(1)
144+
}
145+
146+
setupLog.Info("starting manager")
147+
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
148+
setupLog.Error(err, "problem running manager")
149+
os.Exit(1)
150+
}
151+
}

0 commit comments

Comments
 (0)