diff --git a/cmd/atc/handler.go b/cmd/atc/handler.go index 3227fbd..5f9f389 100644 --- a/cmd/atc/handler.go +++ b/cmd/atc/handler.go @@ -26,6 +26,7 @@ import ( "github.com/yokecd/yoke/internal/k8s" "github.com/yokecd/yoke/internal/wasi" "github.com/yokecd/yoke/pkg/apis/airway/v1alpha1" + "github.com/yokecd/yoke/pkg/flight" "github.com/yokecd/yoke/pkg/yoke" ) @@ -165,16 +166,6 @@ func Handler(client *k8s.Client, cache *wasm.ModuleCache, logger *slog.Logger) h return } - flight := cache.Get(airway.Name).Flight - - flight.RLock() - defer flight.RUnlock() - - if flight.CompiledModule == nil { - http.Error(w, "flight not ready or not registered for custom resource", http.StatusNotFound) - return - } - review.Response = &admissionv1.AdmissionResponse{ UID: review.Request.UID, Allowed: true, @@ -184,7 +175,6 @@ func Handler(client *k8s.Client, cache *wasm.ModuleCache, logger *slog.Logger) h params := yoke.TakeoffParams{ Release: atc.ReleaseName(&cr), Flight: yoke.FlightParams{ - Module: flight.Module, Input: bytes.NewReader(data), Namespace: cr.GetNamespace(), }, @@ -200,6 +190,22 @@ func Handler(client *k8s.Client, cache *wasm.ModuleCache, logger *slog.Logger) h }, } + if overrideURL, _, _ := unstructured.NestedString(cr.Object, "metadata", "annotations", flight.AnnotationOverrideFlight); overrideURL != "" { + addRequestAttrs(r.Context(), slog.Group("overrides", "flight", overrideURL)) + params.Flight.Path = overrideURL + } else { + flightMod := cache.Get(airway.Name).Flight + + flightMod.RLock() + defer flightMod.RUnlock() + + if flightMod.CompiledModule == nil { + http.Error(w, "flight not ready or not registered for custom resource", http.StatusNotFound) + return + } + params.Flight.Module = flightMod.Module + } + ctx := internal.WithStderr(r.Context(), io.Discard) if err := commander.Takeoff(ctx, params); err != nil && !internal.IsWarning(err) { diff --git a/cmd/atc/internal/testing/apis/backend/v2/dev/main.go b/cmd/atc/internal/testing/apis/backend/v2/dev/main.go index d9ba0ea..e650206 100644 --- a/cmd/atc/internal/testing/apis/backend/v2/dev/main.go +++ b/cmd/atc/internal/testing/apis/backend/v2/dev/main.go @@ -31,6 +31,10 @@ func run() error { return err } + if backend.Spec.Replicas%2 == 0 { + return fmt.Errorf("replicas must be odd but got %d", backend.Spec.Replicas) + } + backend.Spec.ServicePort = cmp.Or(backend.Spec.ServicePort, 3000) if backend.Spec.Meta.Labels == nil { diff --git a/cmd/atc/main_test.go b/cmd/atc/main_test.go index e637118..e6daa84 100644 --- a/cmd/atc/main_test.go +++ b/cmd/atc/main_test.go @@ -453,6 +453,31 @@ func TestAirTrafficController(t *testing.T) { return } + // Validations must be performed against the flight override module. The backend/v2/dev module fails if replicas is even. + require.ErrorContains( + t, + commander.Takeoff(ctx, yoke.TakeoffParams{ + Release: "c4ts", + Flight: yoke.FlightParams{ + Input: testutils.JsonReader(backendv2.Backend{ + ObjectMeta: metav1.ObjectMeta{ + Name: "c4ts", + Annotations: map[string]string{ + flight.AnnotationOverrideFlight: "http://wasmcache/flight.dev.wasm", + }, + }, + Spec: backendv2.BackendSpec{ + Img: "yokecd/c4ts:test", + Replicas: 2, + }, + }), + }, + Wait: 30 * time.Second, + Poll: time.Second, + }), + "replicas must be odd but got 2", + ) + require.NoError( t, commander.Takeoff(ctx, yoke.TakeoffParams{ diff --git a/internal/atc/atc.go b/internal/atc/atc.go index bff81f8..014c444 100644 --- a/internal/atc/atc.go +++ b/internal/atc/atc.go @@ -505,9 +505,6 @@ func (atc atc) FlightReconciler(params FlightReconcilerParams) ctrl.HandleFunc { return ctrl.Result{}, fmt.Errorf("failed to marhshal resource: %w", err) } - params.Flight.RLock() - defer params.Flight.RUnlock() - commander := yoke.FromK8Client(ctrl.Client(ctx)) takeoffParams := yoke.TakeoffParams{ @@ -534,6 +531,8 @@ func (atc atc) FlightReconciler(params FlightReconcilerParams) ctrl.HandleFunc { // It is not recommended to override in production. As so it is allowable that users don't version the overrideURL and that the content can change. takeoffParams.Flight.Path = overrideURL } else { + params.Flight.RLock() + defer params.Flight.RUnlock() takeoffParams.Flight.Module = params.Flight.Module }