From 61cdbbb49b2ac22299e7bbcf482b6907bfc2edf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20Burzy=C5=84ski?= Date: Tue, 18 Feb 2025 17:21:08 +0100 Subject: [PATCH] feat: use KIC as a library in ControlPlane controller --- config/rbac/role/role.yaml | 19 +- controller/controlplane/controller.go | 433 ++++++------------ controller/controlplane/controller_consts.go | 3 + controller/controlplane/controller_rbac.go | 7 - .../controller_reconciler_utils.go | 242 ---------- .../controller_reconciler_utils_test.go | 202 -------- controller/controlplane/controller_test.go | 178 ------- controller/controlplane/manager_options.go | 69 +++ controller/gateway/controller_cleanup.go | 2 +- controller/pkg/secrets/cert.go | 4 +- controller/pkg/secrets/cert_test.go | 2 +- go.mod | 52 ++- go.sum | 206 +++++---- modules/manager/controller_setup.go | 9 +- modules/manager/run.go | 12 +- 15 files changed, 408 insertions(+), 1032 deletions(-) delete mode 100644 controller/controlplane/controller_reconciler_utils_test.go create mode 100644 controller/controlplane/manager_options.go diff --git a/config/rbac/role/role.yaml b/config/rbac/role/role.yaml index 30fe76971..1047052dc 100644 --- a/config/rbac/role/role.yaml +++ b/config/rbac/role/role.yaml @@ -8,7 +8,6 @@ rules: - "" resources: - configmaps - - serviceaccounts - services verbs: - create @@ -50,6 +49,12 @@ rules: - get - list - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - delete - apiGroups: - "" resources: @@ -63,13 +68,7 @@ rules: resources: - validatingwebhookconfigurations verbs: - - create - delete - - get - - list - - patch - - update - - watch - apiGroups: - apiextensions.k8s.io resources: @@ -449,10 +448,4 @@ rules: - clusterrolebindings - clusterroles verbs: - - create - delete - - get - - list - - patch - - update - - watch diff --git a/controller/controlplane/controller.go b/controller/controlplane/controller.go index 583ddd042..db4cdec81 100644 --- a/controller/controlplane/controller.go +++ b/controller/controlplane/controller.go @@ -2,36 +2,40 @@ package controlplane import ( "context" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" "errors" "fmt" "strings" "time" + "github.com/cloudflare/cfssl/config" + "github.com/cloudflare/cfssl/signer" + "github.com/cloudflare/cfssl/signer/local" "github.com/go-logr/logr" - admregv1 "k8s.io/api/admissionregistration/v1" - appsv1 "k8s.io/api/apps/v1" + "github.com/kong/kubernetes-ingress-controller/v3/pkg/manager" + managercfg "github.com/kong/kubernetes-ingress-controller/v3/pkg/manager/config" + "github.com/kong/kubernetes-ingress-controller/v3/pkg/manager/multiinstance" + certificatesv1 "k8s.io/api/certificates/v1" corev1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/predicate" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" operatorv1beta1 "github.com/kong/gateway-operator/api/v1beta1" "github.com/kong/gateway-operator/controller" "github.com/kong/gateway-operator/controller/pkg/controlplane" "github.com/kong/gateway-operator/controller/pkg/log" - "github.com/kong/gateway-operator/controller/pkg/op" "github.com/kong/gateway-operator/controller/pkg/secrets" operatorerrors "github.com/kong/gateway-operator/internal/errors" - "github.com/kong/gateway-operator/internal/versions" "github.com/kong/gateway-operator/pkg/consts" gatewayutils "github.com/kong/gateway-operator/pkg/utils/gateway" k8sutils "github.com/kong/gateway-operator/pkg/utils/kubernetes" @@ -45,72 +49,14 @@ type Reconciler struct { ClusterCASecretNamespace string ClusterCAKeyConfig secrets.KeyConfig DevelopmentMode bool + + RestConfig *rest.Config + InstancesManager *multiinstance.Manager } // SetupWithManager sets up the controller with the Manager. -func (r *Reconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error { - // for owned objects we need to check if updates to the objects resulted in the - // removal of an OwnerReference to the parent object, and if so we need to - // enqueue the parent object so that reconciliation can create a replacement. - clusterRoleOwnerPredicate := predicate.NewPredicateFuncs(r.clusterRoleHasControlPlaneOwner) - clusterRoleOwnerPredicate.UpdateFunc = func(e event.UpdateEvent) bool { - return r.clusterRoleHasControlPlaneOwner(e.ObjectOld) - } - clusterRoleBindingOwnerPredicate := predicate.NewPredicateFuncs(r.clusterRoleBindingHasControlPlaneOwner) - clusterRoleBindingOwnerPredicate.UpdateFunc = func(e event.UpdateEvent) bool { - return r.clusterRoleBindingHasControlPlaneOwner(e.ObjectOld) - } - validatinWebhookConfigurationOwnerPredicate := predicate.NewPredicateFuncs(r.validatingWebhookConfigurationHasControlPlaneOwner) - validatinWebhookConfigurationOwnerPredicate.UpdateFunc = func(e event.UpdateEvent) bool { - return r.validatingWebhookConfigurationHasControlPlaneOwner(e.ObjectOld) - } - - return ctrl.NewControllerManagedBy(mgr). - // watch ControlPlane objects - For(&operatorv1beta1.ControlPlane{}). - // watch for changes in Secrets created by the controlplane controller - Owns(&corev1.Secret{}). - // watch for changes in ServiceAccounts created by the controlplane controller - Owns(&corev1.ServiceAccount{}). - // watch for changes in Deployments created by the controlplane controller - Owns(&appsv1.Deployment{}). - // watch for changes in Services created by the controlplane controller - Owns(&corev1.Service{}). - // watch for changes in ValidatingWebhookConfigurations created by the controlplane controller. - // Since the ValidatingWebhookConfigurations are cluster-wide but controlplanes are namespaced, - // we need to manually detect the owner by means of the UID - // (Owns cannot be used in this case) - Watches( - &admregv1.ValidatingWebhookConfiguration{}, - handler.EnqueueRequestsFromMapFunc(r.getControlPlaneForValidatingWebhookConfiguration), - builder.WithPredicates(validatinWebhookConfigurationOwnerPredicate), - ). - // watch for changes in ClusterRoles created by the controlplane controller. - // Since the ClusterRoles are cluster-wide but controlplanes are namespaced, - // we need to manually detect the owner by means of the UID - // (Owns cannot be used in this case) - Watches( - &rbacv1.ClusterRole{}, - handler.EnqueueRequestsFromMapFunc(r.getControlPlaneForClusterRole), - builder.WithPredicates(clusterRoleOwnerPredicate)). - // watch for changes in ClusterRoleBindings created by the controlplane controller. - // Since the ClusterRoleBindings are cluster-wide but controlplanes are namespaced, - // we need to manually detect the owner by means of the UID - // (Owns cannot be used in this case) - Watches( - &rbacv1.ClusterRoleBinding{}, - handler.EnqueueRequestsFromMapFunc(r.getControlPlaneForClusterRoleBinding), - builder.WithPredicates(clusterRoleBindingOwnerPredicate)). - Watches( - &operatorv1beta1.DataPlane{}, - handler.EnqueueRequestsFromMapFunc(r.getControlPlanesFromDataPlane)). - // watch for changes in the DataPlane deployments, as we want to be aware of all - // the DataPlane pod changes (every time a new pod gets ready, the deployment - // status gets updated accordingly, leading to a reconciliation loop trigger) - Watches( - &appsv1.Deployment{}, - handler.EnqueueRequestsFromMapFunc(r.getControlPlanesFromDataPlaneDeployment)). - Complete(r) +func (r *Reconciler) SetupWithManager(_ context.Context, mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr).For(&operatorv1beta1.ControlPlane{}).Complete(r) } // Reconcile moves the current state of an object to the intended state. @@ -123,6 +69,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return ctrl.Result{}, client.IgnoreNotFound(err) } + mgrID, err := manager.NewID(cp.Name) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to create manager ID: %w", err) + } + // controlplane is deleted, just run garbage collection for cluster wide resources. if !cp.DeletionTimestamp.IsZero() { // wait for termination grace period before cleaning up roles and bindings @@ -138,65 +89,22 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu }, nil } - log.Trace(logger, "controlplane marked for deletion, removing owned cluster roles, cluster role bindings and validating webhook configurations") - - newControlPlane := cp.DeepCopy() - - // ensure that the ValidatingWebhookConfigurations which was created for the ControlPlane is deleted - deletions, err := r.ensureOwnedValidatingWebhookConfigurationDeleted(ctx, cp) - if err != nil { - return ctrl.Result{}, err - } - if deletions { - log.Debug(logger, "ValidatingWebhookConfiguration deleted") - return ctrl.Result{}, nil // ValidatingWebhookConfiguration deletion will requeue - } - - // now that ValidatingWebhookConfigurations are cleaned up, remove the relevant finalizer - if controllerutil.RemoveFinalizer(newControlPlane, string(ControlPlaneFinalizerCleanupValidatingWebhookConfiguration)) { - if err := r.Client.Patch(ctx, newControlPlane, client.MergeFrom(cp)); err != nil { - return ctrl.Result{}, err - } - log.Debug(logger, "ValidatingWebhookConfigurations finalizer removed") - return ctrl.Result{}, nil // ControlPlane update will requeue - } - - // ensure that the clusterrolebindings which were created for the ControlPlane are deleted - deletions, err = r.ensureOwnedClusterRoleBindingsDeleted(ctx, cp) - if err != nil { - return ctrl.Result{}, err - } - if deletions { - log.Debug(logger, "clusterRoleBinding deleted") - return ctrl.Result{}, nil // ClusterRoleBinding deletion will requeue - } - - // now that ClusterRoleBindings are cleaned up, remove the relevant finalizer - if controllerutil.RemoveFinalizer(newControlPlane, string(ControlPlaneFinalizerCleanupClusterRoleBinding)) { - if err := r.Client.Patch(ctx, newControlPlane, client.MergeFrom(cp)); err != nil { - return ctrl.Result{}, err + if err := r.InstancesManager.StopInstance(mgrID); err != nil { + if errors.As(err, &multiinstance.InstanceNotFoundError{}) { + log.Debug(logger, "control plane instance not found, skipping cleanup") + } else { + return ctrl.Result{}, fmt.Errorf("failed to stop instance: %w", err) } - log.Debug(logger, "clusterRoleBinding finalizer removed") - return ctrl.Result{}, nil // ControlPlane update will requeue } - // ensure that the clusterroles created for the controlplane are deleted - deletions, err = r.ensureOwnedClusterRolesDeleted(ctx, cp) - if err != nil { - return ctrl.Result{}, err - } - if deletions { - log.Debug(logger, "clusterRole deleted") - return ctrl.Result{}, nil // ClusterRole deletion will requeue - } - - // now that ClusterRoles are cleaned up, remove the relevant finalizer - if controllerutil.RemoveFinalizer(newControlPlane, string(ControlPlaneFinalizerCleanupClusterRole)) { - if err := r.Client.Patch(ctx, newControlPlane, client.MergeFrom(cp)); err != nil { - return ctrl.Result{}, err + // remove finalizer + controllerutil.RemoveFinalizer(cp, string(ControlPlaneFinalizerCPInstanceTeardown)) + if err := r.Client.Update(ctx, cp); err != nil { + if k8serrors.IsConflict(err) { + log.Debug(logger, "conflict found when updating ControlPlane, retrying") + return ctrl.Result{Requeue: true, RequeueAfter: controller.RequeueWithoutBackoff}, nil } - log.Debug(logger, "clusterRole finalizer removed") - return ctrl.Result{}, nil // ControlPlane update will requeue + return ctrl.Result{}, fmt.Errorf("failed updating ControlPlane: %w", err) } // cleanup completed @@ -205,10 +113,8 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } // ensure the controlplane has a finalizer to delete owned cluster wide resources on delete. - crFinalizerSet := controllerutil.AddFinalizer(cp, string(ControlPlaneFinalizerCleanupClusterRole)) - crbFinalizerSet := controllerutil.AddFinalizer(cp, string(ControlPlaneFinalizerCleanupClusterRoleBinding)) - vwcFinalizerSet := controllerutil.AddFinalizer(cp, string(ControlPlaneFinalizerCleanupValidatingWebhookConfiguration)) - if crFinalizerSet || crbFinalizerSet || vwcFinalizerSet { + finalizerSet := controllerutil.AddFinalizer(cp, string(ControlPlaneFinalizerCPInstanceTeardown)) + if finalizerSet { log.Trace(logger, "setting finalizers") if err := r.Client.Update(ctx, cp); err != nil { if k8serrors.IsConflict(err) { @@ -262,11 +168,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } } - log.Trace(logger, "validating ControlPlane configuration") - if err := validateControlPlane(cp, r.DevelopmentMode); err != nil { - return ctrl.Result{}, err - } - log.Trace(logger, "configuring ControlPlane resource") defaultArgs := controlplane.DefaultsArgs{ Namespace: cp.Namespace, @@ -297,18 +198,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return ctrl.Result{}, nil // no need to requeue, the update will trigger. } - log.Trace(logger, "validating that the ControlPlane's DataPlane configuration is up to date") - if err = r.ensureDataPlaneConfiguration(ctx, cp, dataplaneIngressServiceName); err != nil { - if k8serrors.IsConflict(err) { - log.Debug( - logger, - "conflict found when trying to ensure ControlPlane's DataPlane configuration was up to date, retrying", - "controlPlane", cp, - ) - return ctrl.Result{Requeue: true, RequeueAfter: controller.RequeueWithoutBackoff}, nil - } - return ctrl.Result{}, err - } + // TODO(czeslavo): Make sure we reschedule the instance if the spec has changed. log.Trace(logger, "validating ControlPlane's DataPlane status") dataplaneIsSet := r.ensureDataPlaneStatus(cp, dataplane) @@ -318,91 +208,74 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu log.Debug(logger, "DataPlane not set, deployment for ControlPlane will remain dormant") } - log.Trace(logger, "ensuring ServiceAccount for ControlPlane deployment exists") - createdOrUpdated, controlplaneServiceAccount, err := r.ensureServiceAccount(ctx, cp) - if err != nil { - return ctrl.Result{}, err - } - if createdOrUpdated { - log.Debug(logger, "serviceAccount updated") - return ctrl.Result{}, nil // requeue will be triggered by the creation or update of the owned object - } + log.Trace(logger, "checking readiness of ControlPlane instance") + if err := r.InstancesManager.IsInstanceReady(mgrID); err != nil { + log.Trace(logger, "control plane instance not ready yet", "error", err) - log.Trace(logger, "ensuring ClusterRoles for ControlPlane deployment exist") - createdOrUpdated, controlplaneClusterRole, err := r.ensureClusterRole(ctx, cp) - if err != nil { - return ctrl.Result{}, err - } - if createdOrUpdated { - log.Debug(logger, "clusterRole updated") - return ctrl.Result{}, nil // requeue will be triggered by the creation or update of the owned object - } + if errors.As(err, &multiinstance.InstanceNotFoundError{}) { + log.Debug(logger, "control plane instance not found, creating new instance") - log.Trace(logger, "ensuring that ClusterRoleBindings for ControlPlane Deployment exist") - createdOrUpdated, _, err = r.ensureClusterRoleBinding(ctx, cp, controlplaneServiceAccount.Name, controlplaneClusterRole.Name) - if err != nil { - return ctrl.Result{}, err - } - if createdOrUpdated { - log.Debug(logger, "clusterRoleBinding updated") - return ctrl.Result{}, nil // requeue will be triggered by the creation or update of the owned object - } + var caSecret corev1.Secret + if err := r.Get(ctx, types.NamespacedName{ + Namespace: r.ClusterCASecretNamespace, + Name: r.ClusterCASecretName, + }, &caSecret); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to get CA secret: %w", err) + } - log.Trace(logger, "creating mTLS certificate") - res, adminCertificate, err := r.ensureAdminMTLSCertificateSecret(ctx, cp) - if err != nil { - return ctrl.Result{}, err - } - if res != op.Noop { - log.Debug(logger, "mTLS certificate created/updated") - return ctrl.Result{}, nil // requeue will be triggered by the creation or update of the owned object - } + log.Trace(logger, "creating mTLS certificate") + clientCert, clientKey, err := r.generateClientCert(client.ObjectKeyFromObject(cp), caSecret) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to generate client certificate: %w", err) + } - deploymentParams := ensureDeploymentParams{ - ControlPlane: cp, - ServiceAccountName: controlplaneServiceAccount.Name, - AdminMTLSCertSecretName: adminCertificate.Name, - } + mgrCfg, err := manager.NewConfig( + WithRestConfig(r.RestConfig), + WithKongAdminService(types.NamespacedName{ + Name: dataplaneAdminServiceName, + Namespace: cp.Namespace, + }), + WithKongAdminServicePortName(consts.DataPlaneAdminServicePortName), + WithKongAdminInitializationRetryDelay(5*time.Second), + WithGatewayToReconcile(types.NamespacedName{ + Namespace: cp.Namespace, + Name: defaultArgs.OwnedByGateway, + }), + WithGatewayAPIControllerName(), + WithKongAdminAPIConfig(managercfg.AdminAPIClientConfig{ + CACert: string(caSecret.Data["tls.crt"]), + TLSClient: managercfg.TLSClientConfig{ + Cert: string(clientCert), + Key: string(clientKey), + }, + }), + WithDisabledLeaderElection(), + WithPublishService(types.NamespacedName{ + Namespace: cp.Namespace, + Name: dataplaneIngressServiceName, + }), + ) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to create manager config: %w", err) + } - admissionWebhookCertificateSecretName, res, err := r.ensureWebhookResources(ctx, logger, cp) - if err != nil { - return ctrl.Result{}, fmt.Errorf("failed to ensure webhook resources: %w", err) - } else if res != op.Noop { - return ctrl.Result{Requeue: true, RequeueAfter: controller.RequeueWithoutBackoff}, nil - } - deploymentParams.AdmissionWebhookCertSecretName = admissionWebhookCertificateSecretName + // TODO: set POD_NAME and POD_NAMESPACE (or rather change it in the manager to not use env vars) - log.Trace(logger, "looking for existing Deployments for ControlPlane resource") - res, controlplaneDeployment, err := r.ensureDeployment(ctx, logger, deploymentParams) - if err != nil { - return ctrl.Result{}, err - } - if res != op.Noop { - if !dataplaneIsSet { - log.Debug(logger, "DataPlane not set, deployment for ControlPlane has been scaled down to 0 replicas") - res, err := r.patchStatus(ctx, logger, cp) + log.Debug(logger, "creating new instance", "manager_id", mgrID, "manager_config", mgrCfg) + mgr, err := manager.NewManager(ctx, mgrID, logger, mgrCfg) if err != nil { - log.Debug(logger, "unable to reconcile ControlPlane status", "error", err) - return ctrl.Result{}, err + return ctrl.Result{}, fmt.Errorf("failed to create manager: %w", err) } - if !res.IsZero() { - log.Debug(logger, "unable to update ControlPlane resource") - return res, nil + + if err := r.InstancesManager.ScheduleInstance(mgr); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to schedule instance: %w", err) } - return ctrl.Result{}, nil } - return ctrl.Result{}, nil // requeue will be triggered by the creation or update of the owned object - } - log.Trace(logger, "checking readiness of ControlPlane deployments") - if controlplaneDeployment.Status.Replicas == 0 || controlplaneDeployment.Status.AvailableReplicas < controlplaneDeployment.Status.Replicas { - log.Trace(logger, "deployment for ControlPlane not ready yet", "deployment", controlplaneDeployment) - // Set Ready to false for controlplane as the underlying deployment is not ready. k8sutils.SetCondition( k8sutils.NewCondition(consts.ReadyType, metav1.ConditionFalse, consts.WaitingToBecomeReadyReason, consts.WaitingToBecomeReadyMessage), cp, ) - res, err := r.patchStatus(ctx, logger, cp) if err != nil { log.Debug(logger, "unable to patch ControlPlane status", "error", err) @@ -412,7 +285,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu log.Debug(logger, "unable to patch ControlPlane status") return res, nil } - return ctrl.Result{}, nil + + // Give the instance some time to start up. + return ctrl.Result{RequeueAfter: time.Second}, nil } markAsProvisioned(cp) @@ -432,16 +307,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return ctrl.Result{}, nil } -// validateControlPlane validates the control plane. -func validateControlPlane(controlPlane *operatorv1beta1.ControlPlane, devMode bool) error { - versionValidationOptions := make([]versions.VersionValidationOption, 0) - if !devMode { - versionValidationOptions = append(versionValidationOptions, versions.IsControlPlaneImageVersionSupported) - } - _, err := controlplane.GenerateImage(&controlPlane.Spec.ControlPlaneOptions, versionValidationOptions...) - return err -} - // patchStatus Patches the resource status only when there are changes in the Conditions func (r *Reconciler) patchStatus(ctx context.Context, logger logr.Logger, updated *operatorv1beta1.ControlPlane) (ctrl.Result, error) { current := &operatorv1beta1.ControlPlane{} @@ -466,79 +331,73 @@ func (r *Reconciler) patchStatus(ctx context.Context, logger logr.Logger, update return ctrl.Result{}, nil } -func (r *Reconciler) ensureWebhookResources( - ctx context.Context, logger logr.Logger, cp *operatorv1beta1.ControlPlane, -) (string, op.Result, error) { - webhookEnabled := isAdmissionWebhookEnabled(ctx, r.Client, logger, cp) - if !webhookEnabled { - log.Debug(logger, "admission webhook disabled, ensuring admission webhook resources are not present") - } else { - log.Debug(logger, "admission webhook enabled, enforcing admission webhook resources") - } - - log.Trace(logger, "ensuring admission webhook service") - res, admissionWebhookService, err := r.ensureAdmissionWebhookService(ctx, logger, r.Client, cp) +func (r *Reconciler) generateClientCert( + cp types.NamespacedName, + caSecret corev1.Secret, +) ([]byte, []byte, error) { + priv, privPem, signatureAlgorithm, err := secrets.CreatePrivateKey(r.ClusterCAKeyConfig) if err != nil { - return "", res, fmt.Errorf("failed to ensure admission webhook service: %w", err) + return nil, nil, fmt.Errorf("failed to create private key: %w", err) } - if res != op.Noop { - if !webhookEnabled { - log.Debug(logger, "admission webhook service has been removed") - } else { - log.Debug(logger, "admission webhook service has been created/updated") - } - return "", res, nil // requeue will be triggered by the creation or update of the owned object + + subject := fmt.Sprintf("%s.%s", cp.Name, cp.Namespace) + template := x509.CertificateRequest{ + Subject: pkix.Name{ + CommonName: subject, + Organization: []string{"Kong, Inc."}, + Country: []string{"US"}, + }, + SignatureAlgorithm: signatureAlgorithm, + DNSNames: []string{subject}, } - log.Trace(logger, "ensuring admission webhook certificate") - res, admissionWebhookCertificateSecret, err := r.ensureAdmissionWebhookCertificateSecret(ctx, logger, cp, admissionWebhookService) + caCertBlock, _ := pem.Decode(caSecret.Data["tls.crt"]) + if caCertBlock == nil { + return nil, nil, errors.New("failed to decode CA certificate") + } + caCert, err := x509.ParseCertificate(caCertBlock.Bytes) if err != nil { - return "", res, err + return nil, nil, fmt.Errorf("failed to parse CA certificate: %w", err) } - if res != op.Noop { - if !webhookEnabled { - log.Debug(logger, "admission webhook service certificate has been removed") - } else { - log.Debug(logger, "admission webhook service certificate has been created/updated") - } - return "", res, nil // requeue will be triggered by the creation or update of the owned object + caKeyBlock, _ := pem.Decode(caSecret.Data["tls.key"]) + if caKeyBlock == nil { + return nil, nil, errors.New("failed to decode CA key") } - log.Trace(logger, "ensuring admission webhook configuration") - res, err = r.ensureValidatingWebhookConfiguration(ctx, cp, admissionWebhookCertificateSecret, admissionWebhookService) + caSigner, signatureAlgorithm, err := secrets.ParsePrivateKey(caKeyBlock) if err != nil { - return "", res, err - } - if res != op.Noop { - if !webhookEnabled { - log.Debug(logger, "ValidatingWebhookConfiguration has been removed") - } else { - log.Debug(logger, "ValidatingWebhookConfiguration has been created/updated") - } - } - if webhookEnabled { - return admissionWebhookCertificateSecret.Name, res, nil + return nil, nil, fmt.Errorf("failed to parse CA key: %w", err) } - return "", res, nil -} -func isAdmissionWebhookEnabled(ctx context.Context, cl client.Client, logger logr.Logger, cp *operatorv1beta1.ControlPlane) bool { - if cp.Spec.Deployment.PodTemplateSpec == nil { - return false + der, err := x509.CreateCertificateRequest(rand.Reader, &template, priv) + if err != nil { + return nil, nil, fmt.Errorf("failed to create certificate request: %w", err) } - container := k8sutils.GetPodContainerByName(&cp.Spec.Deployment.PodTemplateSpec.Spec, consts.ControlPlaneControllerContainerName) - if container == nil { - return false + policy := &config.Signing{ + Default: &config.SigningProfile{ + Usage: []string{ + string(certificatesv1.UsageKeyEncipherment), + string(certificatesv1.UsageDigitalSignature), + string(certificatesv1.UsageClientAuth), + }, + Expiry: time.Hour * 24 * 365, + }, } - admissionWebhookListen, ok, err := k8sutils.GetEnvValueFromContainer(ctx, container, cp.Namespace, "CONTROLLER_ADMISSION_WEBHOOK_LISTEN", cl) + cfs, err := local.NewSigner(caSigner, caCert, signatureAlgorithm, policy) if err != nil { - log.Debug(logger, "unable to get CONTROLLER_ADMISSION_WEBHOOK_LISTEN env var", "error", err) - return false + return nil, nil, fmt.Errorf("failed to create signer: %w", err) } - if !ok { - return false + + cert, err := cfs.Sign(signer.SignRequest{ + Request: string(pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE REQUEST", + Bytes: der, + })), + }) + if err != nil { + return nil, nil, fmt.Errorf("failed to sign certificate: %w", err) } - // We don't validate the value of the env var here, just that it is set. - return len(admissionWebhookListen) > 0 && admissionWebhookListen != "off" + + return cert, pem.EncodeToMemory(privPem), nil } diff --git a/controller/controlplane/controller_consts.go b/controller/controlplane/controller_consts.go index 230efbd1c..cdc8bf967 100644 --- a/controller/controlplane/controller_consts.go +++ b/controller/controlplane/controller_consts.go @@ -14,4 +14,7 @@ const ( ControlPlaneFinalizerCleanupClusterRoleBinding ControlPlaneFinalizer = "gateway-operator.konghq.com/cleanup-clusterrolebinding" // ControlPlaneFinalizerCleanupValidatingWebhookConfiguration is the finalizer to cleanup validatingwebhookconfigurations owned by controlplane on deleting. ControlPlaneFinalizerCleanupValidatingWebhookConfiguration ControlPlaneFinalizer = "gateway-operator.konghq.com/cleanup-validatingwebhookconfiguration" + + // ControlPlaneFinalizerCPInstanceTeardown is the finalizer to tear down a controlplane instance. + ControlPlaneFinalizerCPInstanceTeardown ControlPlaneFinalizer = "gateway-operator.konghq.com/teardown-cp-instance" ) diff --git a/controller/controlplane/controller_rbac.go b/controller/controlplane/controller_rbac.go index d51ce5665..d19419fd1 100644 --- a/controller/controlplane/controller_rbac.go +++ b/controller/controlplane/controller_rbac.go @@ -7,10 +7,3 @@ package controlplane // +kubebuilder:rbac:groups=gateway-operator.konghq.com,resources=controlplanes,verbs=get;list;watch;update;patch // +kubebuilder:rbac:groups=gateway-operator.konghq.com,resources=controlplanes/status,verbs=update;patch // +kubebuilder:rbac:groups=gateway-operator.konghq.com,resources=controlplanes/finalizers,verbs=update -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles,verbs=create;get;list;watch;update;patch;delete -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterrolebindings,verbs=create;get;list;watch;update;patch;delete -// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=create;get;list;watch;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=services,verbs=create;get;list;watch;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=create;get;list;watch;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch -// +kubebuilder:rbac:groups=admissionregistration.k8s.io,resources=validatingwebhookconfigurations,verbs=get;list;watch;create;update;patch;delete diff --git a/controller/controlplane/controller_reconciler_utils.go b/controller/controlplane/controller_reconciler_utils.go index 8b743b4cd..328c5f2e5 100644 --- a/controller/controlplane/controller_reconciler_utils.go +++ b/controller/controlplane/controller_reconciler_utils.go @@ -8,7 +8,6 @@ import ( "github.com/go-logr/logr" "github.com/google/go-cmp/cmp" "github.com/samber/lo" - admregv1 "k8s.io/api/admissionregistration/v1" appsv1 "k8s.io/api/apps/v1" certificatesv1 "k8s.io/api/certificates/v1" corev1 "k8s.io/api/core/v1" @@ -441,58 +440,6 @@ func (r *Reconciler) ensureAdminMTLSCertificateSecret( ) } -// ensureAdmissionWebhookCertificateSecret ensures that a Secret is created with the serving certificate for the -// ControlPlane's admission webhook. -func (r *Reconciler) ensureAdmissionWebhookCertificateSecret( - ctx context.Context, - logger logr.Logger, - cp *operatorv1beta1.ControlPlane, - admissionWebhookService *corev1.Service, -) ( - op.Result, - *corev1.Secret, - error, -) { - usages := []certificatesv1.KeyUsage{ - certificatesv1.UsageKeyEncipherment, - certificatesv1.UsageServerAuth, - certificatesv1.UsageDigitalSignature, - } - matchingLabels := client.MatchingLabels{ - consts.SecretUsedByServiceLabel: consts.ControlPlaneServiceKindWebhook, - } - if !isAdmissionWebhookEnabled(ctx, r.Client, logger, cp) { - labels := k8sresources.GetManagedLabelForOwner(cp) - labels[consts.SecretUsedByServiceLabel] = consts.ControlPlaneServiceKindWebhook - secrets, err := k8sutils.ListSecretsForOwner(ctx, r.Client, cp.GetUID(), matchingLabels) - if err != nil { - return op.Noop, nil, fmt.Errorf("failed listing Secrets for ControlPlane %s/: %w", client.ObjectKeyFromObject(cp), err) - } - for _, svc := range secrets { - if err := r.Client.Delete(ctx, &svc); err != nil { - return op.Noop, nil, fmt.Errorf("failed deleting ControlPlane admission webhook Secret %s: %w", svc.Name, err) - } - } - if len(secrets) == 0 { - return op.Noop, nil, nil - } - return op.Deleted, nil, nil - } - - return secrets.EnsureCertificate(ctx, - cp, - fmt.Sprintf("%s.%s.svc", admissionWebhookService.Name, admissionWebhookService.Namespace), - k8stypes.NamespacedName{ - Namespace: r.ClusterCASecretNamespace, - Name: r.ClusterCASecretName, - }, - usages, - r.ClusterCAKeyConfig, - r.Client, - matchingLabels, - ) -} - // ensureOwnedClusterRolesDeleted removes all the owned ClusterRoles of the controlplane. // it is called on cleanup of owned cluster resources on controlplane deletion. // returns nil if all of owned ClusterRoles successfully deleted (ok if no owned CRs or NotFound on deleting CRs). @@ -554,192 +501,3 @@ func (r *Reconciler) ensureOwnedClusterRoleBindingsDeleted( return deleted, errors.Join(errs...) } - -func (r *Reconciler) ensureOwnedValidatingWebhookConfigurationDeleted(ctx context.Context, - cp *operatorv1beta1.ControlPlane, -) (deletions bool, err error) { - validatingWebhookConfigurations, err := k8sutils.ListValidatingWebhookConfigurations( - ctx, - r.Client, - client.MatchingLabels(k8sutils.GetManagedByLabelSet(cp)), - ) - if err != nil { - return false, fmt.Errorf("failed listing webhook configurations for owner: %w", err) - } - - var ( - deleted bool - errs []error - ) - for i := range validatingWebhookConfigurations { - if err = r.Client.Delete(ctx, &validatingWebhookConfigurations[i]); client.IgnoreNotFound(err) != nil { - errs = append(errs, err) - continue - } - deleted = true - } - return deleted, errors.Join(errs...) -} - -func (r *Reconciler) ensureAdmissionWebhookService( - ctx context.Context, - logger logr.Logger, - cl client.Client, - cp *operatorv1beta1.ControlPlane, -) (op.Result, *corev1.Service, error) { - matchingLabels := k8sresources.GetManagedLabelForOwner(cp) - matchingLabels[consts.ControlPlaneServiceLabel] = consts.ControlPlaneServiceKindWebhook - - services, err := k8sutils.ListServicesForOwner( - ctx, - cl, - cp.Namespace, - cp.UID, - matchingLabels, - ) - if err != nil { - return op.Noop, nil, fmt.Errorf("failed listing admission webhook Services for ControlPlane %s/%s: %w", cp.Namespace, cp.Name, err) - } - - if !isAdmissionWebhookEnabled(ctx, cl, logger, cp) { - for _, svc := range services { - if err := cl.Delete(ctx, &svc); client.IgnoreNotFound(err) != nil { - return op.Noop, nil, fmt.Errorf("failed deleting ControlPlane admission webhook Service %s: %w", svc.Name, err) - } - } - if len(services) == 0 { - return op.Noop, nil, nil - } - return op.Deleted, nil, nil - } - - count := len(services) - if count > 1 { - if err := k8sreduce.ReduceServices(ctx, cl, services); err != nil { - return op.Noop, nil, err - } - return op.Noop, nil, errors.New("number of ControlPlane admission webhook Services reduced") - } - - generatedService, err := k8sresources.GenerateNewAdmissionWebhookServiceForControlPlane(cp) - if err != nil { - return op.Noop, nil, err - } - - if count == 1 { - var updated bool - existingService := &services[0] - updated, existingService.ObjectMeta = k8sutils.EnsureObjectMetaIsUpdated(existingService.ObjectMeta, generatedService.ObjectMeta) - - if !cmp.Equal(existingService.Spec.Selector, generatedService.Spec.Selector) { - existingService.Spec.Selector = generatedService.Spec.Selector - updated = true - } - if !cmp.Equal(existingService.Spec.Ports, generatedService.Spec.Ports) { - existingService.Spec.Ports = generatedService.Spec.Ports - updated = true - } - - if updated { - if err := cl.Update(ctx, existingService); err != nil { - return op.Noop, existingService, fmt.Errorf("failed updating ControlPlane admission webhook Service %s: %w", existingService.Name, err) - } - return op.Updated, existingService, nil - } - return op.Noop, existingService, nil - } - - if err := cl.Create(ctx, generatedService); err != nil { - return op.Noop, nil, fmt.Errorf("failed creating ControlPlane admission webhook Service: %w", err) - } - - return op.Created, generatedService, nil -} - -func (r *Reconciler) ensureValidatingWebhookConfiguration( - ctx context.Context, - cp *operatorv1beta1.ControlPlane, - certSecret *corev1.Secret, - webhookService *corev1.Service, -) (op.Result, error) { - logger := log.GetLogger(ctx, "controlplane.ensureValidatingWebhookConfiguration", r.DevelopmentMode) - - validatingWebhookConfigurations, err := k8sutils.ListValidatingWebhookConfigurations( - ctx, - r.Client, - client.MatchingLabels(k8sutils.GetManagedByLabelSet(cp)), - ) - if err != nil { - return op.Noop, fmt.Errorf("failed listing webhook configurations for owner: %w", err) - } - - count := len(validatingWebhookConfigurations) - if count > 1 { - if err := k8sreduce.ReduceValidatingWebhookConfigurations(ctx, r.Client, validatingWebhookConfigurations); err != nil { - return op.Noop, err - } - return op.Noop, errors.New("number of validatingWebhookConfigurations reduced") - } - - if !isAdmissionWebhookEnabled(ctx, r.Client, logger, cp) { - for _, webhookConfiguration := range validatingWebhookConfigurations { - if err := r.Client.Delete(ctx, &webhookConfiguration); client.IgnoreNotFound(err) != nil { - return op.Noop, fmt.Errorf("failed deleting ControlPlane admission webhook ValidatingWebhookConfiguration %s: %w", webhookConfiguration.Name, err) - } - } - if len(validatingWebhookConfigurations) == 0 { - return op.Noop, nil - } - return op.Deleted, nil - } - - cpContainer := k8sutils.GetPodContainerByName(&cp.Spec.Deployment.PodTemplateSpec.Spec, consts.ControlPlaneControllerContainerName) - if cpContainer == nil { - return op.Noop, errors.New("controller container not found") - } - - caBundle, ok := certSecret.Data["ca.crt"] - if !ok { - return op.Noop, errors.New("ca.crt not found in secret") - } - generatedWebhookConfiguration, err := k8sresources.GenerateValidatingWebhookConfigurationForControlPlane( - cp.Name, - cpContainer.Image, - r.DevelopmentMode, - admregv1.WebhookClientConfig{ - Service: &admregv1.ServiceReference{ - Namespace: cp.Namespace, - Name: webhookService.GetName(), - Port: lo.ToPtr(int32(consts.ControlPlaneAdmissionWebhookListenPort)), - }, - CABundle: caBundle, - }, - ) - if err != nil { - return op.Noop, fmt.Errorf("failed generating ControlPlane's ValidatingWebhookConfiguration: %w", err) - } - k8sutils.SetOwnerForObjectThroughLabels(generatedWebhookConfiguration, cp) - - if count == 1 { - var updated bool - webhookConfiguration := validatingWebhookConfigurations[0] - old := webhookConfiguration.DeepCopy() - - updated, webhookConfiguration.ObjectMeta = k8sutils.EnsureObjectMetaIsUpdated(webhookConfiguration.ObjectMeta, generatedWebhookConfiguration.ObjectMeta) - - if !cmp.Equal(webhookConfiguration.Webhooks, generatedWebhookConfiguration.Webhooks) || - !cmp.Equal(webhookConfiguration.Labels, generatedWebhookConfiguration.Labels) { - webhookConfiguration.Webhooks = generatedWebhookConfiguration.Webhooks - updated = true - } - - if updated { - log.Debug(logger, "patching existing ValidatingWebhookConfiguration") - return op.Updated, r.Client.Patch(ctx, &webhookConfiguration, client.MergeFrom(old)) - } - - return op.Noop, nil - } - - return op.Created, r.Client.Create(ctx, generatedWebhookConfiguration) -} diff --git a/controller/controlplane/controller_reconciler_utils_test.go b/controller/controlplane/controller_reconciler_utils_test.go deleted file mode 100644 index 4de0814f6..000000000 --- a/controller/controlplane/controller_reconciler_utils_test.go +++ /dev/null @@ -1,202 +0,0 @@ -package controlplane - -import ( - "context" - "testing" - - "github.com/samber/lo" - "github.com/stretchr/testify/require" - admregv1 "k8s.io/api/admissionregistration/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/scheme" - fakectrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client/fake" - - operatorv1beta1 "github.com/kong/gateway-operator/api/v1beta1" - "github.com/kong/gateway-operator/controller/pkg/op" - "github.com/kong/gateway-operator/pkg/consts" - k8sresources "github.com/kong/gateway-operator/pkg/utils/kubernetes/resources" -) - -func Test_ensureValidatingWebhookConfiguration(t *testing.T) { - webhookSvc := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "webhook-svc", - }, - } - - testCases := []struct { - name string - cp *operatorv1beta1.ControlPlane - webhook *admregv1.ValidatingWebhookConfiguration - - testBody func(*testing.T, *Reconciler, *operatorv1beta1.ControlPlane) - }{ - { - name: "creating validating webhook configuration", - cp: &operatorv1beta1.ControlPlane{ - TypeMeta: metav1.TypeMeta{ - Kind: "ControlPlane", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "cp", - }, - Spec: operatorv1beta1.ControlPlaneSpec{ - ControlPlaneOptions: operatorv1beta1.ControlPlaneOptions{ - Deployment: operatorv1beta1.ControlPlaneDeploymentOptions{ - Replicas: lo.ToPtr(int32(1)), - PodTemplateSpec: &corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - func() corev1.Container { - c := k8sresources.GenerateControlPlaneContainer( - k8sresources.GenerateContainerForControlPlaneParams{ - Image: consts.DefaultControlPlaneImage, - AdmissionWebhookCertSecretName: lo.ToPtr("cert-secret"), - }) - // Envs are set elsewhere so fill in the CONTROLLER_ADMISSION_WEBHOOK_LISTEN - // here so that the webhook is enabled. - c.Env = append(c.Env, corev1.EnvVar{ - Name: "CONTROLLER_ADMISSION_WEBHOOK_LISTEN", - Value: "0.0.0.0:8080", - }) - return c - }(), - }, - }, - }, - }, - }, - }, - }, - testBody: func(t *testing.T, r *Reconciler, cp *operatorv1beta1.ControlPlane) { - var ( - ctx = context.Background() - webhooks admregv1.ValidatingWebhookConfigurationList - ) - require.NoError(t, r.Client.List(ctx, &webhooks)) - require.Empty(t, webhooks.Items) - - certSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cert-secret", - }, - Data: map[string][]byte{ - "ca.crt": []byte("ca"), // dummy - }, - } - - res, err := r.ensureValidatingWebhookConfiguration(ctx, cp, certSecret, webhookSvc) - require.NoError(t, err) - require.Equal(t, op.Created, res) - - require.NoError(t, r.Client.List(ctx, &webhooks)) - require.Len(t, webhooks.Items, 1) - - res, err = r.ensureValidatingWebhookConfiguration(ctx, cp, certSecret, webhookSvc) - require.NoError(t, err) - require.Equal(t, op.Noop, res) - }, - }, - { - name: "updating validating webhook configuration enforces ObjectMeta", - cp: &operatorv1beta1.ControlPlane{ - TypeMeta: metav1.TypeMeta{ - Kind: "ControlPlane", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "cp", - }, - Spec: operatorv1beta1.ControlPlaneSpec{ - ControlPlaneOptions: operatorv1beta1.ControlPlaneOptions{ - Deployment: operatorv1beta1.ControlPlaneDeploymentOptions{ - Replicas: lo.ToPtr(int32(1)), - PodTemplateSpec: &corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - func() corev1.Container { - c := k8sresources.GenerateControlPlaneContainer( - k8sresources.GenerateContainerForControlPlaneParams{ - Image: consts.DefaultControlPlaneImage, - AdmissionWebhookCertSecretName: lo.ToPtr("cert-secret"), - }) - // Envs are set elsewhere so fill in the CONTROLLER_ADMISSION_WEBHOOK_LISTEN - // here so that the webhook is enabled. - c.Env = append(c.Env, corev1.EnvVar{ - Name: "CONTROLLER_ADMISSION_WEBHOOK_LISTEN", - Value: "0.0.0.0:8080", - }) - return c - }(), - }, - }, - }, - }, - }, - }, - }, - testBody: func(t *testing.T, r *Reconciler, cp *operatorv1beta1.ControlPlane) { - var ( - ctx = context.Background() - webhooks admregv1.ValidatingWebhookConfigurationList - ) - require.NoError(t, r.Client.List(ctx, &webhooks)) - require.Empty(t, webhooks.Items) - - certSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cert-secret", - }, - Data: map[string][]byte{ - "ca.crt": []byte("ca"), // dummy - }, - } - - res, err := r.ensureValidatingWebhookConfiguration(ctx, cp, certSecret, webhookSvc) - require.NoError(t, err) - require.Equal(t, res, op.Created) - - require.NoError(t, r.Client.List(ctx, &webhooks)) - require.Len(t, webhooks.Items, 1, "webhook configuration should be created") - - res, err = r.ensureValidatingWebhookConfiguration(ctx, cp, certSecret, webhookSvc) - require.NoError(t, err) - require.Equal(t, res, op.Noop) - - t.Log("updating webhook configuration outside of the controller") - { - w := webhooks.Items[0] - w.ObjectMeta.Labels["foo"] = "bar" - require.NoError(t, r.Client.Update(ctx, &w)) - } - - t.Log("running ensureValidatingWebhookConfiguration to enforce ObjectMeta") - res, err = r.ensureValidatingWebhookConfiguration(ctx, cp, certSecret, webhookSvc) - require.NoError(t, err) - require.Equal(t, res, op.Updated) - - require.NoError(t, r.Client.List(ctx, &webhooks)) - require.Len(t, webhooks.Items, 1) - require.NotContains(t, webhooks.Items[0].Labels, "foo", - "labels should be updated by the controller so that changes applied by 3rd parties are overwritten", - ) - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - fakeClient := fakectrlruntimeclient. - NewClientBuilder(). - WithScheme(scheme.Scheme). - WithObjects(tc.cp). - Build() - - r := &Reconciler{ - Client: fakeClient, - } - - tc.testBody(t, r, tc.cp) - }) - } -} diff --git a/controller/controlplane/controller_test.go b/controller/controlplane/controller_test.go index 170eb53ea..3e8fbe574 100644 --- a/controller/controlplane/controller_test.go +++ b/controller/controlplane/controller_test.go @@ -241,184 +241,6 @@ func TestReconciler_Reconcile(t *testing.T) { require.NoError(t, err) }, }, - { - name: "invalid ControlPlane image", - controlplaneReq: reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: "test-namespace", - Name: "test-controlplane", - }, - }, - controlplane: &operatorv1beta1.ControlPlane{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "gateway-operator.konghq.com/v1beta1", - Kind: "ControlPlane", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-controlplane", - Namespace: "test-namespace", - UID: types.UID(uuid.NewString()), - Finalizers: []string{ - string(ControlPlaneFinalizerCleanupClusterRole), - string(ControlPlaneFinalizerCleanupClusterRoleBinding), - string(ControlPlaneFinalizerCleanupValidatingWebhookConfiguration), - }, - }, - Spec: operatorv1beta1.ControlPlaneSpec{ - ControlPlaneOptions: operatorv1beta1.ControlPlaneOptions{ - Deployment: operatorv1beta1.ControlPlaneDeploymentOptions{ - PodTemplateSpec: &corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Name: consts.ControlPlaneControllerContainerName, - Image: "kong/kubernetes-ingress-controller:1.0", - }, - }, - }, - }, - }, - DataPlane: lo.ToPtr("test-dataplane"), - }, - }, - Status: operatorv1beta1.ControlPlaneStatus{ - Conditions: []metav1.Condition{ - { - Type: string(ConditionTypeProvisioned), - Status: metav1.ConditionTrue, - }, - }, - }, - }, - dataplane: &operatorv1beta1.DataPlane{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "gateway-operator.konghq.com/v1beta1", - Kind: "DataPlane", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-dataplane", - Namespace: "test-namespace", - UID: types.UID(uuid.NewString()), - }, - Spec: operatorv1beta1.DataPlaneSpec{ - DataPlaneOptions: operatorv1beta1.DataPlaneOptions{ - Deployment: operatorv1beta1.DataPlaneDeploymentOptions{ - DeploymentOptions: operatorv1beta1.DeploymentOptions{ - PodTemplateSpec: &corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Name: consts.DataPlaneProxyContainerName, - Image: "kong:1.0", - }, - }, - }, - }, - }, - }, - }, - }, - Status: operatorv1beta1.DataPlaneStatus{ - Conditions: []metav1.Condition{ - { - Type: string(consts.ReadyType), - Status: metav1.ConditionTrue, - }, - }, - }, - }, - dataplanePods: []controllerruntimeclient.Object{ - &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "dataplane-pod", - Namespace: "test-namespace", - Labels: map[string]string{ - "app": "test-dataplane", - }, - CreationTimestamp: metav1.Now(), - }, - Status: corev1.PodStatus{ - PodIP: "1.2.3.4", - }, - }, - }, - controlplaneSubResources: []controllerruntimeclient.Object{ - &corev1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-tls-secret", - Namespace: "test-namespace", - Labels: map[string]string{ - "app": "test-controlplane", - consts.GatewayOperatorManagedByLabel: consts.ControlPlaneManagedLabelValue, - }, - }, - }, - &rbacv1.ClusterRole{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-serviceAccount", - Namespace: "test-namespace", - Labels: map[string]string{ - "app": "test-controlplane", - consts.GatewayOperatorManagedByLabel: consts.ControlPlaneManagedLabelValue, - }, - }, - }, - &rbacv1.ClusterRoleBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-clusterRole", - Namespace: "test-namespace", - Labels: map[string]string{ - "app": "test-controlplane", - consts.GatewayOperatorManagedByLabel: consts.ControlPlaneManagedLabelValue, - }, - }, - }, - &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-clusterRoleBin", - Namespace: "test-namespace", - Labels: map[string]string{ - "app": "test-controlplane", - consts.GatewayOperatorManagedByLabel: consts.ControlPlaneManagedLabelValue, - }, - }, - }, - }, - dataplaneSubResources: []controllerruntimeclient.Object{ - &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-proxy-service", - Namespace: "test-namespace", - Labels: map[string]string{ - consts.DataPlaneServiceTypeLabel: string(consts.DataPlaneIngressServiceLabelValue), - consts.GatewayOperatorManagedByLabel: consts.DataPlaneManagedLabelValue, - }, - }, - Spec: corev1.ServiceSpec{ - ClusterIP: corev1.ClusterIPNone, - }, - }, - &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-admin-service", - Namespace: "test-namespace", - Labels: map[string]string{ - consts.DataPlaneServiceTypeLabel: string(consts.DataPlaneAdminServiceLabelValue), - consts.GatewayOperatorManagedByLabel: consts.DataPlaneManagedLabelValue, - }, - }, - Spec: corev1.ServiceSpec{ - ClusterIP: corev1.ClusterIPNone, - }, - }, - }, - testBody: func(t *testing.T, reconciler Reconciler, controlplaneReq reconcile.Request) { - ctx := context.Background() - - _, err := reconciler.Reconcile(ctx, controlplaneReq) - require.EqualError(t, err, "unsupported ControlPlane image kong/kubernetes-ingress-controller:1.0") - }, - }, } for _, tc := range testCases { diff --git a/controller/controlplane/manager_options.go b/controller/controlplane/manager_options.go new file mode 100644 index 000000000..e05cc202f --- /dev/null +++ b/controller/controlplane/manager_options.go @@ -0,0 +1,69 @@ +package controlplane + +import ( + "time" + + managercfg "github.com/kong/kubernetes-ingress-controller/v3/pkg/manager/config" + "github.com/samber/mo" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/rest" + + "github.com/kong/gateway-operator/pkg/vars" +) + +func WithRestConfig(restCfg *rest.Config) managercfg.Opt { + return func(c *managercfg.Config) { + c.APIServerHost = restCfg.Host + c.APIServerCertData = restCfg.CertData + c.APIServerKeyData = restCfg.KeyData + c.APIServerCAData = restCfg.CAData + } +} + +func WithKongAdminService(s types.NamespacedName) managercfg.Opt { + return func(c *managercfg.Config) { + c.KongAdminSvc = mo.Some(s) + } +} + +func WithKongAdminServicePortName(portName string) managercfg.Opt { + return func(c *managercfg.Config) { + c.KongAdminSvcPortNames = []string{portName} + } +} + +func WithKongAdminInitializationRetryDelay(delay time.Duration) managercfg.Opt { + return func(c *managercfg.Config) { + c.KongAdminInitializationRetryDelay = delay + } +} + +func WithGatewayToReconcile(gateway types.NamespacedName) managercfg.Opt { + return func(c *managercfg.Config) { + c.GatewayToReconcile = mo.Some(gateway) + } +} + +func WithGatewayAPIControllerName() managercfg.Opt { + return func(c *managercfg.Config) { + c.GatewayAPIControllerName = vars.ControllerName() + } +} + +func WithKongAdminAPIConfig(cfg managercfg.AdminAPIClientConfig) managercfg.Opt { + return func(c *managercfg.Config) { + c.KongAdminAPIConfig = cfg + } +} + +func WithDisabledLeaderElection() managercfg.Opt { + return func(c *managercfg.Config) { + c.LeaderElectionForce = "disabled" + } +} + +func WithPublishService(service types.NamespacedName) managercfg.Opt { + return func(c *managercfg.Config) { + c.PublishService = mo.Some(service) + } +} diff --git a/controller/gateway/controller_cleanup.go b/controller/gateway/controller_cleanup.go index 920dce07a..9280cdf70 100644 --- a/controller/gateway/controller_cleanup.go +++ b/controller/gateway/controller_cleanup.go @@ -149,7 +149,7 @@ func (r *Reconciler) cleanup( } log.Debug(logger, "owned resources cleanup completed") - return false, ctrl.Result{}, nil + return true, ctrl.Result{}, nil } func handleGatewayFinalizerPatchOrUpdateError(err error, logger logr.Logger) (ctrl.Result, error) { diff --git a/controller/pkg/secrets/cert.go b/controller/pkg/secrets/cert.go index 90d7a966b..d87443fed 100644 --- a/controller/pkg/secrets/cert.go +++ b/controller/pkg/secrets/cert.go @@ -133,7 +133,7 @@ func signCertificate( return nil, fmt.Errorf("failed decoding 'tls.key' data from secret %s", ca.Name) } - priv, signatureAlgorithm, err := parsePrivateKey(caKeyBlock) + priv, signatureAlgorithm, err := ParsePrivateKey(caKeyBlock) if err != nil { return nil, err } @@ -437,7 +437,7 @@ func ensureContainerImageUpdated(container *corev1.Container, imageVersionStr st return updated, nil } -func parsePrivateKey(pemBlock *pem.Block) (crypto.Signer, x509.SignatureAlgorithm, error) { +func ParsePrivateKey(pemBlock *pem.Block) (crypto.Signer, x509.SignatureAlgorithm, error) { var ( signatureAlgorithm x509.SignatureAlgorithm = x509.UnknownSignatureAlgorithm priv crypto.Signer diff --git a/controller/pkg/secrets/cert_test.go b/controller/pkg/secrets/cert_test.go index a61e1a10d..f9fb1b536 100644 --- a/controller/pkg/secrets/cert_test.go +++ b/controller/pkg/secrets/cert_test.go @@ -502,7 +502,7 @@ func Test_parsePrivateKey(t *testing.T) { Bytes: privKeyBytes, } - priv, alg, err := parsePrivateKey(pemBlock) + priv, alg, err := ParsePrivateKey(pemBlock) if tt.expectedErrorMsg != "" { require.Error(t, err) assert.Equal(t, tt.expectedErrorMsg, err.Error()) diff --git a/go.mod b/go.mod index 84db9450b..b98bf6433 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ go 1.24.0 retract v1.2.2 require ( - github.com/Kong/sdk-konnect-go v0.2.12 + github.com/Kong/sdk-konnect-go v0.2.13 github.com/Masterminds/semver v1.5.0 github.com/cloudflare/cfssl v1.6.5 github.com/go-logr/logr v1.4.2 @@ -48,10 +48,10 @@ require ( require ( cel.dev/expr v0.20.0 // indirect - cloud.google.com/go/auth v0.10.2 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.5 // indirect + cloud.google.com/go/auth v0.14.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect cloud.google.com/go/compute/metadata v0.6.0 // indirect - cloud.google.com/go/container v1.38.1 // indirect + cloud.google.com/go/container v1.42.2 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/BurntSushi/toml v1.4.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect @@ -102,7 +102,7 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/docker v27.5.0+incompatible // indirect + github.com/docker/docker v27.5.1+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect @@ -121,7 +121,6 @@ require ( github.com/go-openapi/swag v0.23.0 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/gonvenience/bunt v1.3.5 // indirect github.com/gonvenience/neat v1.3.12 // indirect @@ -135,10 +134,10 @@ require ( github.com/google/go-github/v48 v48.2.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/s2a-go v0.1.8 // indirect + github.com/google/s2a-go v0.1.9 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect - github.com/googleapis/gax-go/v2 v2.14.0 // indirect + github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect github.com/gruntwork-io/go-commons v0.8.0 // indirect @@ -201,7 +200,6 @@ require ( github.com/xlab/treeprint v1.2.0 // indirect github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300 // indirect github.com/zmap/zlint/v3 v3.5.0 // indirect - go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect go.opentelemetry.io/otel v1.34.0 // indirect @@ -229,16 +227,49 @@ require ( require ( golang.org/x/sync v0.11.0 // indirect - google.golang.org/api v0.206.0 // indirect + google.golang.org/api v0.220.0 // indirect google.golang.org/grpc v1.70.0 // indirect sigs.k8s.io/kind v0.24.0 // indirect sigs.k8s.io/kustomize/kyaml v0.19.0 ) +require github.com/kong/kubernetes-ingress-controller/v3 v3.4.1-0.20250219153920-f1a789cac529 + require ( + dario.cat/mergo v1.0.1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/Kong/go-diff v1.2.2 // indirect + github.com/Kong/gojsondiff v1.3.2 // indirect + github.com/adrg/strutil v0.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/dominikbraun/graph v0.23.0 // indirect + github.com/fatih/color v1.17.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/google/btree v1.1.3 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-memdb v1.3.4 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hexops/gotextdiff v1.0.3 // indirect + github.com/jpillora/backoff v1.0.0 // indirect github.com/klauspost/compress v1.17.11 // indirect + github.com/kong/go-database-reconciler v1.16.1 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect + github.com/shirou/gopsutil/v3 v3.24.5 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/ssgelm/cookiejarparser v1.0.1 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect + github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect golang.org/x/oauth2 v0.26.0 // indirect golang.org/x/sys v0.30.0 // indirect @@ -250,6 +281,7 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/cli-runtime v0.32.1 // indirect k8s.io/component-base v0.32.2 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect diff --git a/go.sum b/go.sum index bc4dbd17b..0f84c8f56 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,17 @@ cel.dev/expr v0.20.0 h1:OunBvVCfvpWlt4dN7zg3FM6TDkzOePe1+foGJ9AXeeI= cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/auth v0.10.2 h1:oKF7rgBfSHdp/kuhXtqU/tNDr0mZqhYbEh+6SiqzkKo= -cloud.google.com/go/auth v0.10.2/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= -cloud.google.com/go/auth/oauth2adapt v0.2.5 h1:2p29+dePqsCHPP1bqDJcKj4qxRyYCcbzKpFyKGt3MTk= -cloud.google.com/go/auth/oauth2adapt v0.2.5/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= +cloud.google.com/go v0.118.0 h1:tvZe1mgqRxpiVa3XlIGMiPcEUbP1gNXELgD4y/IXmeQ= +cloud.google.com/go v0.118.0/go.mod h1:zIt2pkedt/mo+DQjcT4/L3NDxzHPR29j5HcclNH+9PM= +cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0= +cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= +cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= +cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= -cloud.google.com/go/container v1.38.1 h1:Pb0GbZIg/KS4A9gbF3J4JHmrgPpBA2y+4v9N04aJkOs= -cloud.google.com/go/container v1.38.1/go.mod h1:2r4Qiz6IG2LhRFfWhPNmrYD7yzdE2B2kghigVWoSw/g= +cloud.google.com/go/container v1.42.2 h1:8ncSEBjkng6ucCICauaUGzBomoM2VyYzleAum1OFcow= +cloud.google.com/go/container v1.42.2/go.mod h1:y71YW7uR5Ck+9Vsbst0AF2F3UMgqmsN4SP8JR9xEsR8= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= @@ -18,12 +19,20 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg6 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/Kong/sdk-konnect-go v0.2.12 h1:TjP+cqMLzY0fucHZlY9bxDQWWKJWsaL13EBO0luMzUE= -github.com/Kong/sdk-konnect-go v0.2.12/go.mod h1:xsmTIkBbmVyUh1nRFjQMOhxYIPDl+sMfmRmPuZHtwLE= +github.com/Kong/go-diff v1.2.2 h1:KKKaqHc8IxuguFVIZMNt3bi6YuC/t9r7BGD8bOOpSgM= +github.com/Kong/go-diff v1.2.2/go.mod h1:nlvdwVZQk3Rm+tbI0cDmKFrOjghtcZTrZBp+UruvvA8= +github.com/Kong/gojsondiff v1.3.2 h1:qIOVq2mUXt+NXy8Be5gRUee9TP3Ve0MbQSafg9bXKZE= +github.com/Kong/gojsondiff v1.3.2/go.mod h1:DiIxtU59q4alK7ecP+7k56C5UjgOviJ5gQVR2esEhYw= +github.com/Kong/sdk-konnect-go v0.2.13 h1:WMuxzfO1BTcmUINF3pboiuXp5sFmunKwCXy7tjMeGHc= +github.com/Kong/sdk-konnect-go v0.2.13/go.mod h1:xsmTIkBbmVyUh1nRFjQMOhxYIPDl+sMfmRmPuZHtwLE= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/adrg/strutil v0.3.0 h1:bi/HB2zQbDihC8lxvATDTDzkT4bG7PATtVnDYp5rvq4= +github.com/adrg/strutil v0.3.0/go.mod h1:Jz0wzBVE6Uiy9wxo62YEqEY1Nwto3QlLl1Il5gkLKWU= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -115,13 +124,12 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8 github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= 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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= +github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/cloudflare/cfssl v1.6.5 h1:46zpNkm6dlNkMZH/wMW22ejih6gIaJbzL2du6vD7ZeI= github.com/cloudflare/cfssl v1.6.5/go.mod h1:Bk1si7sq8h2+yVEDrFJiz3d7Aw+pfjjJSZVaD+Taky4= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -130,31 +138,35 @@ github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v27.5.0+incompatible h1:um++2NcQtGRTz5eEgO6aJimo6/JxrTXC941hd05JO6U= -github.com/docker/docker v27.5.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.5.1+incompatible h1:4PYU5dnBYqRQi0294d1FBECqT9ECWeQAIfE8q4YnPY8= +github.com/docker/docker v27.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= +github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 h1:R/ZjJpjQKsZ6L/+Gf9WHbt31GG8NMVcpRqUE+1mMIyo= github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ= github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= @@ -177,6 +189,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= @@ -193,20 +207,8 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/gonvenience/bunt v1.3.5 h1:wSQquifvwEWtzn27k1ngLfeLaStyt0k1b/K6TrlCNAs= @@ -229,13 +231,7 @@ github.com/google/certificate-transparency-go v1.1.7 h1:IASD+NtgSTJLPdzkthwvAG1Z github.com/google/certificate-transparency-go v1.1.7/go.mod h1:FSSBo8fyMVgqptbfF6j5p/XNdgQftAhSmXcIxV9iphE= github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -252,21 +248,22 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= -github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= -github.com/googleapis/gax-go/v2 v2.14.0 h1:f+jMrjBPl+DL9nI4IQzLUxMq7XrAqFYB7hBPqMNIe8o= -github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= +github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= +github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M= github.com/gruntwork-io/go-commons v0.8.0 h1:k/yypwrPqSeYHevLlEDmvmgQzcyTwrlZGRaxEM6G0ro= @@ -275,8 +272,27 @@ github.com/gruntwork-io/terratest v0.48.2 h1:+VwfODchq8jxZZWD+s8gBlhD1z6/C4bFLNr github.com/gruntwork-io/terratest v0.48.2/go.mod h1:Y5ETyD4ZQ2MZhasPno272fWuCpKwvTPYDi8Y0tIMqTE= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c= +github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/homeport/dyff v1.6.0 h1:AN+ikld0Fy+qx34YE7655b/bpWuxS6cL9k852pE2GUc= github.com/homeport/dyff v1.6.0/go.mod h1:FlAOFYzeKvxmU5nTrnG+qrlJVWpsFew7pt8L99p5q8k= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= @@ -299,16 +315,22 @@ github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/kong/go-database-reconciler v1.16.1 h1:qcQzEuMGfpNjx3UgulBOKulKA+upmHwqw4dy6TMEV7A= +github.com/kong/go-database-reconciler v1.16.1/go.mod h1:7CGvStUvUOmUnodUFsWcW3PX2bJgnaKClJ/yhNGEVIE= github.com/kong/go-kong v0.63.0 h1:8ECLgkgDqON61qCMq/M0gTwZKYxg55Oy692dRDOOBiU= github.com/kong/go-kong v0.63.0/go.mod h1:ma9GWnhkxtrXZlLFfED955HjVzmUojYEHet3lm+PDik= github.com/kong/kubernetes-configuration v1.1.1-0.20250219125458-b45dead920d4 h1:cKGIpPM55LOJ2YEbbuKDj/OyJ4Zvz38c/gUJ/zi/JT8= github.com/kong/kubernetes-configuration v1.1.1-0.20250219125458-b45dead920d4/go.mod h1:bTJv/IsSCE9Ux+9RY9fEMCU9yehBWAvrSXc8iWx7OGo= +github.com/kong/kubernetes-ingress-controller/v3 v3.4.1-0.20250219153920-f1a789cac529 h1:sdpCvROsthqsyYfNqeEt+pr4sm85xUPSmy43iGwjVfU= +github.com/kong/kubernetes-ingress-controller/v3 v3.4.1-0.20250219153920-f1a789cac529/go.mod h1:U+oXNG+/GTYJWw4HrykEDvcYPDV6m8BGSLjlw1YmDfw= github.com/kong/kubernetes-telemetry v0.1.8 h1:nbtUmXW9xkzRO7dgvrgVrJZiRksATk4XHrqX+78g/5k= github.com/kong/kubernetes-telemetry v0.1.8/go.mod h1:ZEQY/4DddKoe5XA7UTOIbdI/4d6ZRcrzh2ezRxnuyl0= github.com/kong/kubernetes-testing-framework v0.47.2 h1:+2Z9anTpbV/hwNeN+NFQz53BMU+g3QJydkweBp3tULo= @@ -327,15 +349,24 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= +github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik= +github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3 h1:BXxTozrOU8zgC5dkpn3J6NTRdoP+hjok/e+ACr4Hibk= github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3/go.mod h1:x1uk6vxTiVuNt6S5R2UYgdhpj3oKojXvOXauHZ7dEnI= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= @@ -348,6 +379,8 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/hashstructure v1.1.0 h1:P6P1hdjqAAknpY/M1CGipelZgp+4y9ja9kmUZPXP+H0= github.com/mitchellh/hashstructure v1.1.0/go.mod h1:xUDAozZz0Wmdiufv0uyhnHkUTN6/6d8ulp4AwfLKrmA= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -388,17 +421,22 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig= +github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v1.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA= github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= @@ -419,6 +457,12 @@ github.com/samber/mo v1.13.0 h1:LB1OwfJMju3a6FjghH+AIvzMG0ZPOzgTWj1qaHs1IQ4= github.com/samber/mo v1.13.0/go.mod h1:BfkrCPuYzVG3ZljnZB783WIJIGk1mcZr9c9CPf8tAxs= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= +github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -433,6 +477,8 @@ github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3k github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/ssgelm/cookiejarparser v1.0.1 h1:cRdXauUbOTFzTPJFaeiWbHnQ+tRGlpKKzvIK9PUekE4= +github.com/ssgelm/cookiejarparser v1.0.1/go.mod h1:DUfC0mpjIzlDN7DzKjXpHj0qMI5m9VrZuz3wSlI+OEI= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -461,6 +507,12 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tonglil/buflogr v1.1.1 h1:CKAjOHBSMmgbRFxpn/RhQHPj5oANc7ekhlsoUDvcZIg= +github.com/tonglil/buflogr v1.1.1/go.mod h1:WLLtPRLqcFYWQLbA+ytXy5WrFTYnfA+beg1MpvJCxm4= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= @@ -473,11 +525,24 @@ github.com/weppos/publicsuffix-go v0.30.0/go.mod h1:kBi8zwYnR0zrbm8RcuN1o9Fzgpnn github.com/weppos/publicsuffix-go/publicsuffix/generator v0.0.0-20220927085643-dc0d00c92642/go.mod h1:GHfoeIdZLdZmLjMlzBftbTDntahTttUMWjxZwQJhULE= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.2-0.20150410014804-be8315415630+incompatible h1:TmF93o7P81230DTx1l2zw5rZbsDpOOQXoKVCa8+nXXI= +github.com/yudai/pp v2.0.2-0.20150410014804-be8315415630+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -533,24 +598,17 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs= golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -563,11 +621,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -575,22 +630,27 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -611,10 +671,6 @@ golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -628,33 +684,14 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/api v0.206.0 h1:A27GClesCSheW5P2BymVHjpEeQ2XHH8DI8Srs2HI2L8= -google.golang.org/api v0.206.0/go.mod h1:BtB8bfjTYIrai3d8UyvPmV9REGgox7coh+ZRwm0b+W8= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/api v0.220.0 h1:3oMI4gdBgB72WFVwE1nerDD8W3HUOS4kypK6rRLbGns= +google.golang.org/api v0.220.0/go.mod h1:26ZAlY6aN/8WgpCzjPNy18QpYaz7Zgg1h0qe1GkZEmY= google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b h1:i+d0RZa8Hs2L/MuaOQYI+krthcxdEbEM2N+Tf3kJ4zk= google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4= google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b h1:FQtJ1MxbXoIIrZHZ33M+w5+dAP9o86rgpjoKr/ZmT7k= google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -669,6 +706,7 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -678,8 +716,6 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw= k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y= k8s.io/apiextensions-apiserver v0.32.2 h1:2YMk285jWMk2188V2AERy5yDwBYrjgWYggscghPCvV4= @@ -688,6 +724,8 @@ k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ= k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= k8s.io/apiserver v0.32.2 h1:WzyxAu4mvLkQxwD9hGa4ZfExo3yZZaYzoYvvVDlM6vw= k8s.io/apiserver v0.32.2/go.mod h1:PEwREHiHNU2oFdte7BjzA1ZyjWjuckORLIK/wLV5goM= +k8s.io/cli-runtime v0.32.2 h1:aKQR4foh9qeyckKRkNXUccP9moxzffyndZAvr+IXMks= +k8s.io/cli-runtime v0.32.2/go.mod h1:a/JpeMztz3xDa7GCyyShcwe55p8pbcCVQxvqZnIwXN8= k8s.io/client-go v0.32.2 h1:4dYCD4Nz+9RApM2b/3BtVvBHw54QjMFUl1OLcJG5yOA= k8s.io/client-go v0.32.2/go.mod h1:fpZ4oJXclZ3r2nDOv+Ux3XcJutfrwjKTCHz2H3sww94= k8s.io/component-base v0.32.2 h1:1aUL5Vdmu7qNo4ZsE+569PV5zFatM9hl+lb3dEea2zU= @@ -700,6 +738,8 @@ 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-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg= k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas= +k8s.io/kubectl v0.32.2 h1:TAkag6+XfSBgkqK9I7ZvwtF0WVtUAvK8ZqTt+5zi1Us= +k8s.io/kubectl v0.32.2/go.mod h1:+h/NQFSPxiDZYX/WZaWw9fwYezGLISP0ud8nQKg+3g8= k8s.io/kubernetes v1.32.2 h1:mShetlA102UpjRVSGzB+5vjJwy8oPy8FMWrkTH5f37o= k8s.io/kubernetes v1.32.2/go.mod h1:tiIKO63GcdPRBHW2WiUFm3C0eoLczl3f7qi56Dm1W8I= k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= diff --git a/modules/manager/controller_setup.go b/modules/manager/controller_setup.go index 70d6e173e..f313335f0 100644 --- a/modules/manager/controller_setup.go +++ b/modules/manager/controller_setup.go @@ -6,6 +6,7 @@ import ( "reflect" "time" + "github.com/kong/kubernetes-ingress-controller/v3/pkg/manager/multiinstance" "github.com/samber/lo" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -121,8 +122,8 @@ const ( ) // SetupControllersShim runs SetupControllers and returns its result as a slice of the map values. -func SetupControllersShim(mgr manager.Manager, c *Config) ([]ControllerDef, error) { - controllers, err := SetupControllers(mgr, c) +func SetupControllersShim(mgr manager.Manager, c *Config, cpsMgr *multiinstance.Manager) ([]ControllerDef, error) { + controllers, err := SetupControllers(mgr, c, cpsMgr) if err != nil { return []ControllerDef{}, err } @@ -189,7 +190,7 @@ func setupIndexes(ctx context.Context, mgr manager.Manager, cfg Config) error { } // SetupControllers returns a list of ControllerDefs based on config. -func SetupControllers(mgr manager.Manager, c *Config) (map[string]ControllerDef, error) { +func SetupControllers(mgr manager.Manager, c *Config, cpsMgr *multiinstance.Manager) (map[string]ControllerDef, error) { ctx := context.Background() // metricRecorder is the recorder used to record custom metrics in the controller manager's metrics server. metricRecorder := metrics.NewGlobalCtrlRuntimeMetricsRecorder() @@ -421,6 +422,8 @@ func SetupControllers(mgr manager.Manager, c *Config) (map[string]ControllerDef, ClusterCASecretNamespace: c.ClusterCASecretNamespace, ClusterCAKeyConfig: clusterCAKeyConfig, DevelopmentMode: c.DevelopmentMode, + RestConfig: mgr.GetConfig(), + InstancesManager: cpsMgr, }, }, // DataPlane controller diff --git a/modules/manager/run.go b/modules/manager/run.go index 2c3e4790d..c028a1806 100644 --- a/modules/manager/run.go +++ b/modules/manager/run.go @@ -30,6 +30,7 @@ import ( "time" "github.com/go-logr/logr" + "github.com/kong/kubernetes-ingress-controller/v3/pkg/manager/multiinstance" "github.com/samber/lo" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -116,7 +117,7 @@ func DefaultConfig() Config { // SetupControllersFunc represents function to setup controllers, which is called // in Run function. -type SetupControllersFunc func(manager.Manager, *Config) ([]ControllerDef, error) +type SetupControllersFunc func(manager.Manager, *Config, *multiinstance.Manager) ([]ControllerDef, error) // Run runs the manager. Parameter cfg represents the configuration for the manager // that for normal operation is derived from command-line flags. The function @@ -216,7 +217,12 @@ func Run( return err } - controllers, err := setupControllers(mgr, &cfg) + cpInstancesMgr := multiinstance.NewManager(mgr.GetLogger()) + if err := mgr.Add(cpInstancesMgr); err != nil { + return fmt.Errorf("unable to add CP instances manager: %w", err) + } + + controllers, err := setupControllers(mgr, &cfg, cpInstancesMgr) if err != nil { setupLog.Error(err, "failed setting up controllers") return err @@ -231,7 +237,7 @@ func Run( return fmt.Errorf("unable to set up ready check: %w", err) } - //+kubebuilder:scaffold:builder + // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { return fmt.Errorf("unable to set up health check: %w", err)