wip: auto-bootstrap plural on crossplane#3791
Conversation
Soffi AI SummaryThis PR introduces automatic bootstrapping of Plural-managed clusters provisioned via Crossplane, specifically targeting AWS EKS clusters created through the Crossplane AWS provider. Previously, clusters created through Crossplane had no automated path to registration with the Plural Console — this change closes that gap by adding a new What was added:
Dependency changes: The Commits
Updated: 2026-07-01 13:39 UTC |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Greptile SummaryThis PR adds a new
Confidence Score: 3/5The controller can permanently skip deploying the Plural agent into the target cluster if Helm happens to be busy during the first reconciliation pass. When go/deployment-operator/internal/controller/pluralcrossplanecluster_controller.go — specifically the Helm "in progress" fallthrough around line 143.
|
| Filename | Overview |
|---|---|
| go/deployment-operator/internal/controller/pluralcrossplanecluster_controller.go | New controller for PluralCrossplaneCluster; contains a bug where the spec hash is persisted even when the Helm agent deployment returns an "in progress" error, preventing future reconciliation retries. |
| go/deployment-operator/internal/crossplane/cluster.go | Well-structured ManagedCluster interface, connection secret resolution, and kubeconfig extraction utilities; logic is clean and tested. |
| go/deployment-operator/internal/crossplane/aws_eks.go | Local mirror types for AWS EKS Crossplane clusters (crossplane-contrib and upbound v1beta1/v1beta2) with proper DeepCopy implementations; no issues found. |
| go/deployment-operator/internal/crossplane/aws_cluster_auth.go | Hydrates connection secret config from a ClusterAuth resource when the cluster itself has none; unfiltered cluster-wide List could cause false matches at scale. |
| go/deployment-operator/internal/crossplane/provider.go | Provider dispatch with explicit ErrUnsupportedProvider sentinel; extensible structure for future GKE/AKS support. |
| go/deployment-operator/internal/crossplane/scheme.go | Registers all three AWS EKS GVKs (crossplane-contrib v1beta1, upbound v1beta1, upbound v1beta2) into a runtime Scheme; straightforward and tested. |
| go/deployment-operator/api/v1alpha1/pluralcrossplanecluster_types.go | CRD type definitions and helper methods for PluralCrossplaneCluster; clean implementation with proper attribute conversion for Console API. |
| go/deployment-operator/cmd/agent/kubernetes.go | Registers PluralCrossplaneClusterController with the manager; consistent with existing controller registration pattern in the file. |
| go/deployment-operator/cmd/agent/main.go | Adds crossplane scheme to the global scheme via AddToScheme; minimal, correct change. |
Reviews (1): Last reviewed commit: "plural crossplane cluster" | Re-trigger Greptile
| } | ||
| return ctrl.Result{}, err | ||
| } | ||
|
|
||
| if err = in.deployAgent(pluralCrossplaneCluster, kubeconfig, deployToken); err != nil { | ||
| if !strings.Contains(err.Error(), "another operation (install/upgrade/rollback) is in progress") { | ||
| logger.Error(err, "failed to deploy agent") | ||
| return reconcile.Result{}, err | ||
| } | ||
| } | ||
|
|
||
| pluralCrossplaneCluster.Status.SHA = lo.ToPtr(sha) |
There was a problem hiding this comment.
SHA saved when Helm is still in-progress, blocking future retries
When deployAgent returns the "another operation is in progress" error, the code falls through to lines 150–153, saving the spec hash to Status.SHA and marking ReadyConditionType as True. On the next reconciliation, the HasID() && !changed early-exit fires and the controller returns immediately — the agent install is never retried. The cluster will appear Ready in Console even though the Helm chart was never successfully deployed.
| list := &unstructured.UnstructuredList{} | ||
| list.SetGroupVersionKind(authGV.WithKind("ClusterAuthList")) | ||
| if err := c.List(ctx, list); err != nil { | ||
| return nil, false, err | ||
| } |
There was a problem hiding this comment.
Unfiltered cluster-wide list of ClusterAuth objects
c.List without any ListOptions fetches every ClusterAuth across all namespaces. This is not wrong today, but if many clusters exist the first matching ClusterAuth whose clusterName/clusterNameRef happens to equal the target name wins — even if it lives in an unrelated namespace. Passing an explicit namespace option (or the cluster's own namespace) would scope the search and avoid false matches.
| list := &unstructured.UnstructuredList{} | |
| list.SetGroupVersionKind(authGV.WithKind("ClusterAuthList")) | |
| if err := c.List(ctx, list); err != nil { | |
| return nil, false, err | |
| } | |
| list := &unstructured.UnstructuredList{} | |
| list.SetGroupVersionKind(authGV.WithKind("ClusterAuthList")) | |
| if err := c.List(ctx, list, k8sClient.InNamespace(corev1.NamespaceAll)); err != nil { | |
| return nil, false, err | |
| } |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Test Plan
Test environment: https://console.your-env.onplural.sh/
Checklist
Plural Flow: console