Attribute GitOps-managed objects only to local destinations - #1886
Conversation
An Argo CD Application that deploys to another cluster, or a Flux Kustomization with spec.kubeConfig, lists objects in that cluster. On a hub, the same chart deploys everywhere, so those lists name objects that also exist locally, and topology edges, application source refs and the GitOps tree picked whichever Application came first. Only GitOps objects that deploy to this cluster now claim local objects; remote Flux objects are marked remote in the GitOps tree the same way Argo ones are.
PR Summary by QodoRestrict GitOps attribution to local cluster destinations
AI Description
Diagram
High-Level Assessment
Files changed (10)
|
Code Review by Qodo
1.
|
A HelmRelease has no inventory, so its GitOps tree and topology edges come from local workloads carrying its Helm labels. A release with spec.kubeConfig installed nothing here, so neither path matches it against local workloads.
799ad7d to
61c46a3
Compare
A HelmRelease with spec.kubeConfig no longer marks a same-named local Helm release as Flux-managed, and a remote-destination Application's name no longer vouches for a local app.kubernetes.io/instance label in the GitOps coverage audit.
…f remote ones An Argo Application with no destination is invalid (Argo reports InvalidSpecError and deploys nothing), so it no longer counts as local: its status.resources may name objects of a destination it no longer has. It is not reported as deploying to another cluster either; Argo's condition already explains it. A sync that failed on a missing namespace no longer offers the one-click "create namespace" fix when the Application deploys elsewhere, since it would create the namespace on this cluster. The diagnosis stays and the next step names the namespace to create on the destination cluster.
Summary
On a GitOps hub cluster, one Argo CD instance deploys the same chart to several clusters:
sealed-secrets-eks-prod-cluster,sealed-secrets-eks-nonprod-clusterandsealed-secrets-eks-infra-clustereach list asealed-secrets/sealed-secretsDeployment instatus.resources. Radar joined every Application's list against local objects, so the hub's own Deployment was attributed to whichever Application came first. That was often another cluster's, and it could change between runs. This PR attributes local objects only to GitOps objects that deploy to this cluster.What changed
Argo CD: an Application whose destination isn't this cluster (
gitops.IsInClusterDestination:kubernetes.default.svcorin-cluster) no longer claims local objects. An Application with no destination at all is invalid (Argo reportsInvalidSpecErrorand deploys nothing), so it claims nothing locally either; itsstatus.resourcesmay be left over from a destination it no longer names. Radar shows it through Argo's condition rather than as an app deploying elsewhere. This applies to topologymanagesedges and to Applications source refs. The GitOps tree, insights and diff already used this rule; attribution now follows it too.Flux: a Kustomization with
spec.kubeConfigapplies to another cluster (newgitops.FluxTargetsLocalCluster). Its inventory no longer claims local objects in topology or Applications, and its GitOps tree is markedremoteDestinationlike a remote Argo Application, so nothing local (health, metadata, children) is joined to its entries.Helm and audit: a remote HelmRelease no longer marks a same-named local Helm release as Flux-managed (Helm ownership, upgrade guidance, MCP release output). A remote Application's name no longer counts as evidence that a local workload's
app.kubernetes.io/instancelabel is Argo-managed in the GitOps coverage audit.No local fixes for remote failures: when a remote Application's sync fails on a missing namespace, the GitOps detail page and the Issues view no longer offer the one-click "create namespace" fix, which would create it on this cluster. The diagnosis stays, and the next step names the namespace to create on the destination cluster (or the
CreateNamespace=truesync option).Hub-side claims (
argoManagedWorkloads, matched against destination rows by the hub) are unchanged.Review focus
kubernetes.default.svc/in-cluster, count as remote under this rule and lose attribution rather than risk a wrong one. The Argo hubs checked all use the in-cluster forms for their own deployments. Matching a destination against the connected API server would have to change the tree, insights and diff paths too, and is left for a follow-up that applies it everywhere.kubeConfigpoints back at this same cluster counts as remote, the same trade-off as above.Testing
go test ./...in both Go modules.main: topology edges and Applications source refs with an in-cluster and a remote Application listing the same Deployment (only the in-cluster one claims it); a remote Kustomization claims nothing locally; a remote Kustomization's GitOps tree reads nothing local; a remote HelmRelease claims no local Helm release; a remote Application doesn't vouch for a local instance label in audit; a destinationless Application is neither local nor reported remote; a remote Application's missing-namespace failure offers no local fix, while a local one keeps it.mainwith requests paired:mainpointed the hub's own apps at another cluster's Application (e.g.ingress-nginx-eks-infra-cluster→ingress-nginx-eks-prod-cluster); with this change each points at itself, and every changed resource owner names this cluster's Application.InvalidSpecError;guestbook-broken-sync(local) keeps its create-namespace fix.