You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(apiserver): decide the API server migration from live cluster state
On a direct upgrade from the deprecated API server layout, the apiserver
controller moved the API server into calico-system and repointed the
v3.projectcalico.org APIService at it before the leftover
allow-tigera.default-deny policy had been removed. That policy sits in the
earlier-evaluated allow-tigera tier and selects all() endpoints, so it denied the
moved pod at end-of-tier and the pod never became ready. The aggregated API then
stayed down permanently, because removing the policy requires the API server that
had just been taken out of service.
The controller now decides whether to perform the move by reading live state
through an uncached reader, so the decision cannot be made from cached state that
is no longer true: only v3.LicenseKey is excluded from the manager cache, so a
cached read of a projectcalico.org/v3 object is served from the informer's last
known contents even when the aggregated API cannot serve.
The v3.projectcalico.org APIService supplies both inputs, and the kube-apiserver
serves it directly, so reading it does not depend on the thing being measured.
spec.service.namespace says which layout is deployed; the Available condition
reports the aggregator's own most recent verdict on whether requests can be
served. A migration is pending only while that APIService still points into
tigera-system, so an upgrade that has already moved the API server does not wait
on a policy that can no longer select the pod.
When a migration is pending and the aggregated API can serve, the move waits for
the deprecated policy to be removed by the installation controller. When a
migration is pending and the aggregated API cannot serve, nothing is applied at
all: the trap cannot be confirmed gone and nothing can clear it while the API is
down, so moving would only repoint the aggregated API onto a pod that cannot be
vouched for. The periodic reconcile already registered in Add() retriggers the
decision, and an unrecognised decision holds rather than proceeding, since failing
open on this gate is not recoverable.
Two unsound tests are removed. The tigera-system namespace fallback treated the
namespace's absence as proof the gate had passed; that does not hold on a two-hop
upgrade, where the intermediate release deletes the namespace while leaving the
policy in place, nor after an administrator deletes the namespace to clear a stuck
upgrade. The NoMatch exemption treated a missing RESTMapper mapping as proof the
policy was absent, which is not evidence about the policy at all.
On the pass that performs the migration the projectcalico.org/v3 NetworkPolicy
component is applied before the workload rather than after it, removing the window
in which the moved pod runs with no policy of its own. Every other pass keeps the
existing order, which exists so that a fresh install is not blocked on an API
server that cannot become available until the install has progressed.
Refs: EV-6821
// Do not apply anything. We cannot confirm the deprecated deny is gone, and
529
+
// nothing can clear it while the aggregated API is unable to serve, so moving
530
+
// the workload now could only make the situation harder to recover. The
531
+
// periodic reconcile re-runs this every utils.PeriodicReconcileTime regardless
532
+
// of the requeue below.
533
+
reqLogger.Info("The projectcalico.org/v3 API is unavailable and the API server has not been migrated; holding the migration until it can serve")
534
+
r.status.SetDegraded(operatorv1.ResourceNotReady, "Waiting for the projectcalico.org/v3 API to become available before migrating the API server", nil, reqLogger)
// The deny is removed by the installation controller only after it renders v3
538
+
// NetworkPolicy into the calico-system tier (pkg/render/kubecontrollers/kube-controllers.go),
539
+
// which it only does once the tiers controller has created that tier
540
+
// (pkg/controller/installation/core_controller.go), which the tiers controller only
541
+
// does once IsProjectCalicoV3Available reports APIServer.Status.State == Ready
542
+
// (pkg/controller/tiers/tiers_controller.go). This controller is the only writer of
543
+
// that field, and it does so on a path this hold returns before reaching. On a
544
+
// supported upgrade that field was already persisted by the previous operator version
545
+
// before this reconcile ever ran, so the wait clears on its own; this is not a bug in
546
+
// the upgrade path. It would only spin forever if that status were never latched - for
547
+
// example the tigera-secure APIServer CR was deleted and recreated around the upgrade.
548
+
// Holding is still correct in that case: the alternative is repointing the aggregated
549
+
// API onto a pod the deny traps, which is a worse and equally permanent failure, while
550
+
// holding here leaves the cluster recoverable.
551
+
reqLogger.Info("Waiting for the deprecated allow-tigera.default-deny policy to be removed before migrating the API server")
552
+
r.status.SetDegraded(operatorv1.ResourceNotReady, "Waiting for the deprecated allow-tigera.default-deny policy in calico-system to be removed before migrating the API server; this clears once the installation controller deletes that policy", nil, reqLogger)
// If the projectcalico.org/v3 API group is being backed by our aggregated API server, then v3 NetworkPolicy will fail to reconcile until the Calico API server is healthy.
606
-
// Thus, we only render v3.NetworkPolicy after the aggregated API server becomes available to avoid a chicken-and-egg scenario.
607
-
//
608
-
// If the projectcalico.org/v3 API group is implemented using CRDs natively, we can install network policies immediately, as there is no
609
-
// dependency on the API server deployment.
610
-
//
611
-
// We do this last to avoid transient errors with policy preventing progression of the controller.
0 commit comments