fix(operator): validate CRD apiVersion, respect SIGTERM during install
- Check both apiVersion and kind when validating embedded CRD manifests to prevent applying objects with wrong API group - Move ctrl.SetupSignalHandler() before install phases so CRD and Flux installs respect SIGTERM instead of blocking for up to 2 minutes - Replace custom contains/searchString helpers with strings.Contains Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
This commit is contained in:
parent
abd644122f
commit
cecc5861af
3 changed files with 11 additions and 20 deletions
|
|
@ -180,10 +180,13 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Set up signal handler early so install phases respect SIGTERM
|
||||
mgrCtx := ctrl.SetupSignalHandler()
|
||||
|
||||
// Install Cozystack CRDs before starting reconcile loop
|
||||
if installCRDs {
|
||||
setupLog.Info("Installing Cozystack CRDs before starting reconcile loop")
|
||||
installCtx, installCancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
installCtx, installCancel := context.WithTimeout(mgrCtx, 2*time.Minute)
|
||||
defer installCancel()
|
||||
|
||||
if err := crdinstall.Install(installCtx, directClient, crdinstall.WriteEmbeddedManifests); err != nil {
|
||||
|
|
@ -196,7 +199,7 @@ func main() {
|
|||
// Install Flux before starting reconcile loop
|
||||
if installFlux {
|
||||
setupLog.Info("Installing Flux components before starting reconcile loop")
|
||||
installCtx, installCancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||
installCtx, installCancel := context.WithTimeout(mgrCtx, 5*time.Minute)
|
||||
defer installCancel()
|
||||
|
||||
// Use direct client for pre-start operations (cache is not ready yet)
|
||||
|
|
@ -210,7 +213,7 @@ func main() {
|
|||
// Generate and install platform source resource if specified
|
||||
if platformSourceURL != "" {
|
||||
setupLog.Info("Generating platform source resource", "url", platformSourceURL, "name", platformSourceName, "ref", platformSourceRef)
|
||||
installCtx, installCancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
installCtx, installCancel := context.WithTimeout(mgrCtx, 2*time.Minute)
|
||||
defer installCancel()
|
||||
|
||||
// Use direct client for pre-start operations (cache is not ready yet)
|
||||
|
|
@ -292,7 +295,6 @@ func main() {
|
|||
}
|
||||
|
||||
setupLog.Info("Starting controller manager")
|
||||
mgrCtx := ctrl.SetupSignalHandler()
|
||||
if err := mgr.Start(mgrCtx); err != nil {
|
||||
setupLog.Error(err, "problem running manager")
|
||||
os.Exit(1)
|
||||
|
|
|
|||
|
|
@ -83,9 +83,9 @@ func Install(ctx context.Context, k8sClient client.Client, writeEmbeddedManifest
|
|||
// Validate all objects are CRDs — reject anything else to prevent
|
||||
// accidental force-apply of arbitrary resources.
|
||||
for _, obj := range objects {
|
||||
if obj.GetKind() != "CustomResourceDefinition" {
|
||||
return fmt.Errorf("unexpected object %s/%s in CRD manifests, only CustomResourceDefinition is allowed",
|
||||
obj.GetKind(), obj.GetName())
|
||||
if obj.GetAPIVersion() != "apiextensions.k8s.io/v1" || obj.GetKind() != "CustomResourceDefinition" {
|
||||
return fmt.Errorf("unexpected object %s %s/%s in CRD manifests, only apiextensions.k8s.io/v1 CustomResourceDefinition is allowed",
|
||||
obj.GetAPIVersion(), obj.GetKind(), obj.GetName())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package manifestutil
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -160,7 +161,7 @@ func TestWaitForCRDsEstablished_timeout(t *testing.T) {
|
|||
if err == nil {
|
||||
t.Fatal("WaitForCRDsEstablished() expected error on timeout, got nil")
|
||||
}
|
||||
if !contains(err.Error(), "packages.cozystack.io") {
|
||||
if !strings.Contains(err.Error(), "packages.cozystack.io") {
|
||||
t.Errorf("error should mention stuck CRD name, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -176,15 +177,3 @@ func TestWaitForCRDsEstablished_empty(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func contains(s, substr string) bool {
|
||||
return len(s) >= len(substr) && searchString(s, substr)
|
||||
}
|
||||
|
||||
func searchString(s, substr string) bool {
|
||||
for i := 0; i <= len(s)-len(substr); i++ {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue