diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 973da47..770e663 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -14,6 +14,18 @@ rules: - list - update - watch +- apiGroups: + - butler.butlerlabs.dev + resources: + - butlerconfigs + - loadbalancerrequests + verbs: + - create + - get + - list + - patch + - update + - watch - apiGroups: - butler.butlerlabs.dev resources: @@ -41,6 +53,21 @@ rules: - get - patch - update +- apiGroups: + - butler.butlerlabs.dev + resources: + - imagesyncs + verbs: + - create + - get + - list + - watch +- apiGroups: + - butler.butlerlabs.dev + resources: + - loadbalancerrequests/status + verbs: + - get - apiGroups: - butler.butlerlabs.dev resources: diff --git a/go.mod b/go.mod index 2fe8c71..aa7db4a 100644 --- a/go.mod +++ b/go.mod @@ -5,12 +5,12 @@ go 1.24.6 require ( github.com/onsi/ginkgo/v2 v2.22.0 github.com/onsi/gomega v1.36.1 - k8s.io/apimachinery v0.34.1 - k8s.io/client-go v0.34.1 - sigs.k8s.io/controller-runtime v0.22.4 + k8s.io/apimachinery v0.34.3 + k8s.io/client-go v0.34.3 + sigs.k8s.io/controller-runtime v0.22.5 ) -require github.com/butlerdotdev/butler-api v0.15.0 +require github.com/butlerdotdev/butler-api v0.17.0 require ( cel.dev/expr v0.24.0 // indirect @@ -87,10 +87,10 @@ require ( gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.1 - k8s.io/apiextensions-apiserver v0.34.1 // indirect - k8s.io/apiserver v0.34.1 // indirect - k8s.io/component-base v0.34.1 // indirect + k8s.io/api v0.34.3 + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/apiserver v0.34.3 // indirect + k8s.io/component-base v0.34.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect diff --git a/go.sum b/go.sum index 4a26b43..0d6caab 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/butlerdotdev/butler-api v0.15.0 h1:re+6YTS/CbBspGPK2Z6BO/OxNVXZHemOWqZ/pIE4s2U= -github.com/butlerdotdev/butler-api v0.15.0/go.mod h1:q/RjPFM/r2ELq4DqR78OiAxerKBvH5D4nTGsVLKbjqY= +github.com/butlerdotdev/butler-api v0.17.0 h1:crwV63B8Yedtewmqr4oBJvIdysi/O8k3LjponZwnm1U= +github.com/butlerdotdev/butler-api v0.17.0/go.mod h1:q/RjPFM/r2ELq4DqR78OiAxerKBvH5D4nTGsVLKbjqY= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -229,18 +229,18 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM= -k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk= -k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI= -k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc= -k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4= -k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA= -k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0= -k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY= -k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= -k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A= -k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= +k8s.io/component-base v0.34.3 h1:zsEgw6ELqK0XncCQomgO9DpUIzlrYuZYA0Cgo+JWpVk= +k8s.io/component-base v0.34.3/go.mod h1:5iIlD8wPfWE/xSHTRfbjuvUul2WZbI2nOUK65XL0E/c= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA= @@ -249,8 +249,8 @@ k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327UfMq9A= -sigs.k8s.io/controller-runtime v0.22.4/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= +sigs.k8s.io/controller-runtime v0.22.5 h1:v3nfSUMowX/2WMp27J9slwGFyAt7IV0YwBxAkrUr0GE= +sigs.k8s.io/controller-runtime v0.22.5/go.mod h1:pc5SoYWnWI6I+cBHYYdZ7B6YHZVY5xNfll88JB+vniI= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= diff --git a/internal/addons/installer.go b/internal/addons/installer.go index 965a959..67b874d 100644 --- a/internal/addons/installer.go +++ b/internal/addons/installer.go @@ -100,11 +100,11 @@ type GCPCredentials struct { // AWSCredentials contains IAM credentials and VPC config. type AWSCredentials struct { AccessKeyID string - SecretAccessKey string - Region string - VPCID string - SubnetID string - SecurityGroupID string + SecretAccessKey string + Region string + VPCID string + SubnetID string + SecurityGroupID string } // AzureCredentials contains Azure service principal and resource group config. @@ -406,7 +406,7 @@ func (i *Installer) InstallCilium(ctx context.Context, kubeconfig []byte, versio defer cleanup() if version == "" { - version = "1.17.0" + version = "1.19.4" } logger.Info("Installing Cilium", "version", version) @@ -466,7 +466,7 @@ func (i *Installer) InstallCertManager(ctx context.Context, kubeconfig []byte, v defer cleanup() if version == "" { - version = "v1.16.2" + version = "v1.20.2" } logger.Info("Installing cert-manager", "version", version) @@ -510,7 +510,7 @@ func (i *Installer) InstallLonghorn(ctx context.Context, kubeconfig []byte, vers defer cleanup() if version == "" { - version = "1.7.2" + version = "1.11.2" } if replicaCount == 0 { replicaCount = 2 @@ -1074,7 +1074,7 @@ func (i *Installer) InstallGatewayAPI(ctx context.Context, kubeconfig []byte, ve defer cleanup() if version == "" { - version = "v1.2.1" + version = "v1.5.1" } logger.Info("Installing Gateway API CRDs", "version", version) @@ -1115,7 +1115,7 @@ func (i *Installer) InstallSteward(ctx context.Context, kubeconfig []byte, versi defer cleanup() if version == "" { - version = "0.3.0" + version = "0.4.0" } logger.Info("Installing Steward", "version", version) @@ -1219,7 +1219,7 @@ func (i *Installer) InstallButlerCRDs(ctx context.Context, kubeconfig []byte, ve } if version == "" { - version = "0.6.0" + version = "0.20.0" } args := []string{ @@ -1266,7 +1266,7 @@ func (i *Installer) InstallButlerAddons(ctx context.Context, kubeconfig []byte, defer cleanup() if version == "" { - version = "0.1.0" + version = "0.8.4" } args := []string{ @@ -1843,7 +1843,7 @@ func (i *Installer) InstallCAPI(ctx context.Context, kubeconfig []byte, version // Install Steward CAPI provider manually // Use server-side apply to avoid annotation size limit (CRD is too large for client-side apply) logger.Info("Installing Steward CAPI provider manually") - stewardURL := "https://github.com/butlerdotdev/cluster-api-control-plane-provider-steward/releases/download/v0.1.0/control-plane-components.yaml" + stewardURL := "https://github.com/butlerdotdev/cluster-api-control-plane-provider-steward/releases/download/v0.3.0/control-plane-components.yaml" if err := i.runKubectl(ctx, kubeconfigPath, "apply", "--server-side", "--force-conflicts", "-f", stewardURL); err != nil { return fmt.Errorf("failed to install Steward CAPI provider: %w", err) } @@ -1913,22 +1913,22 @@ func (i *Installer) installInfraProvider(ctx context.Context, kubeconfigPath str providerURL = "https://github.com/kubernetes-sigs/cluster-api-provider-kubevirt/releases/download/v0.1.9/infrastructure-components.yaml" case "nutanix": namespace = "capx-system" - providerURL = "https://github.com/nutanix-cloud-native/cluster-api-provider-nutanix/releases/download/v1.4.0/infrastructure-components.yaml" + providerURL = "https://github.com/nutanix-cloud-native/cluster-api-provider-nutanix/releases/download/v1.8.4/infrastructure-components.yaml" case "vsphere": namespace = "capv-system" - providerURL = "https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/releases/download/v1.11.0/infrastructure-components.yaml" + providerURL = "https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/releases/download/v1.16.1/infrastructure-components.yaml" case "proxmox": namespace = "capmox-system" - providerURL = "https://github.com/ionos-cloud/cluster-api-provider-proxmox/releases/download/v0.6.0/infrastructure-components.yaml" + providerURL = "https://github.com/ionos-cloud/cluster-api-provider-proxmox/releases/download/v0.8.1/infrastructure-components.yaml" case "gcp": namespace = "capg-system" - providerURL = "https://github.com/kubernetes-sigs/cluster-api-provider-gcp/releases/download/v1.8.0/infrastructure-components.yaml" + providerURL = "https://github.com/kubernetes-sigs/cluster-api-provider-gcp/releases/download/v1.11.2/infrastructure-components.yaml" case "aws": namespace = "capa-system" - providerURL = "https://github.com/kubernetes-sigs/cluster-api-provider-aws/releases/download/v2.7.0/infrastructure-components.yaml" + providerURL = "https://github.com/kubernetes-sigs/cluster-api-provider-aws/releases/download/v2.11.1/infrastructure-components.yaml" case "azure": namespace = "capz-system" - providerURL = "https://github.com/kubernetes-sigs/cluster-api-provider-azure/releases/download/v1.17.0/infrastructure-components.yaml" + providerURL = "https://github.com/kubernetes-sigs/cluster-api-provider-azure/releases/download/v1.24.0/infrastructure-components.yaml" default: logger.Info("Unknown provider, skipping", "provider", provider) return nil @@ -2132,7 +2132,7 @@ func (i *Installer) InstallButlerController(ctx context.Context, kubeconfig []by } if version == "" { - version = "0.12.2" + version = "0.27.0" } repo, tag := splitImageRef(image) @@ -2188,7 +2188,7 @@ func splitImageRef(ref string) (string, string) { func (i *Installer) InstallConsole(ctx context.Context, kubeconfig []byte, spec *butlerv1alpha1.ConsoleAddonSpec, clusterName string, provider string) (string, error) { logger := log.FromContext(ctx) - version := "0.4.1" + version := "0.13.1" if spec != nil && spec.Version != "" && !strings.EqualFold(spec.Version, "latest") { version = spec.Version } @@ -2212,11 +2212,7 @@ func (i *Installer) InstallConsole(ctx context.Context, kubeconfig []byte, spec return "", fmt.Errorf("failed to prepare steward-system namespace: %w", err) } - // Build helm values - values := []string{ - "server.image.tag=latest", - "frontend.image.tag=latest", - } + values := []string{} // Configure ingress if enabled if spec != nil && spec.Ingress != nil && spec.Ingress.Enabled { diff --git a/internal/controller/clusterbootstrap_controller.go b/internal/controller/clusterbootstrap_controller.go index 192f207..c48cfa1 100644 --- a/internal/controller/clusterbootstrap_controller.go +++ b/internal/controller/clusterbootstrap_controller.go @@ -1032,7 +1032,7 @@ func (r *ClusterBootstrapReconciler) reconcileInstallingAddons(ctx context.Conte // Install before Steward so the CRDs exist when Steward starts watching them if !r.isAddonInstalled(cb, "gateway-api") { logger.Info("Installing Gateway API CRDs") - if err := r.AddonInstaller.InstallGatewayAPI(ctx, kubeconfig, "v1.2.0"); err != nil { + if err := r.AddonInstaller.InstallGatewayAPI(ctx, kubeconfig, "v1.5.1"); err != nil { logger.Error(err, "Failed to install Gateway API CRDs") return ctrl.Result{RequeueAfter: requeueShort}, nil } @@ -1155,7 +1155,7 @@ func (r *ClusterBootstrapReconciler) reconcileInstallingAddons(ctx context.Conte if addons.IsButlerControllerEnabled() { if !r.isAddonInstalled(cb, "butler-addons") { logger.Info("Installing Butler addon definitions") - if err := r.AddonInstaller.InstallButlerAddons(ctx, kubeconfig, "0.1.0"); err != nil { + if err := r.AddonInstaller.InstallButlerAddons(ctx, kubeconfig, "0.8.4"); err != nil { logger.Error(err, "Failed to install Butler addon definitions") return ctrl.Result{RequeueAfter: requeueShort}, nil } @@ -1520,7 +1520,7 @@ func (r *ClusterBootstrapReconciler) getProviderCredentials(ctx context.Context, logger.Info("Retrieved GCP credentials", "projectID", creds.GCP.ProjectID, "region", creds.GCP.Region) case "aws": creds.AWS = &addons.AWSCredentials{ - AccessKeyID: string(secret.Data["accessKeyID"]), + AccessKeyID: string(secret.Data["accessKeyID"]), SecretAccessKey: string(secret.Data["secretAccessKey"]), Region: providerConfig.Spec.AWS.Region, } @@ -1644,7 +1644,7 @@ func (r *ClusterBootstrapReconciler) extractProviderCredentials(ctx context.Cont return nil, fmt.Errorf("ProviderConfig %s has no aws configuration", providerConfigKey) } creds.AWS = &addons.AWSCredentials{ - AccessKeyID: string(secret.Data["accessKeyID"]), + AccessKeyID: string(secret.Data["accessKeyID"]), SecretAccessKey: string(secret.Data["secretAccessKey"]), Region: providerConfig.Spec.AWS.Region, VPCID: providerConfig.Spec.AWS.VPCID, @@ -1928,11 +1928,11 @@ func (r *ClusterBootstrapReconciler) reconcileImageSync(ctx context.Context, cb Name: imageSyncName, Namespace: cb.Namespace, Labels: map[string]string{ - butlerv1alpha1.LabelManagedBy: "butler", - butlerv1alpha1.LabelSchematicID: labelSchematicID, - butlerv1alpha1.LabelImageVersion: version, - butlerv1alpha1.LabelProviderConfig: cb.Spec.ProviderRef.Name, - butlerv1alpha1.LabelImageArch: arch, + butlerv1alpha1.LabelManagedBy: "butler", + butlerv1alpha1.LabelSchematicID: labelSchematicID, + butlerv1alpha1.LabelImageVersion: version, + butlerv1alpha1.LabelProviderConfig: cb.Spec.ProviderRef.Name, + butlerv1alpha1.LabelImageArch: arch, }, OwnerReferences: []metav1.OwnerReference{ {