From 1791a5157711df7cbf017ec94a15e29d88b0f46b Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Tue, 24 Jan 2023 15:59:51 +0100 Subject: [PATCH 01/15] retrieves kubernetes version on server --- internal/helper/kubernetes/version.go | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 internal/helper/kubernetes/version.go diff --git a/internal/helper/kubernetes/version.go b/internal/helper/kubernetes/version.go new file mode 100644 index 00000000..0f2b748f --- /dev/null +++ b/internal/helper/kubernetes/version.go @@ -0,0 +1,33 @@ +package kubernetes + +import ( + "strconv" + + discovery "k8s.io/client-go/discovery" + "k8s.io/client-go/rest" +) + +type Version struct { + Major int + Minor int +} + +func GetVersion(cfg *rest.Config) (*Version, error) { + client := discovery.NewDiscoveryClientForConfigOrDie(cfg) + version, err := client.ServerVersion() + if err != nil { + return nil, err + } + + major, err := strconv.Atoi(version.Major) + if err != nil { + return nil, err + } + + minor, err := strconv.Atoi(version.Minor) + if err != nil { + return nil, err + } + + return &Version{Major: major, Minor: minor}, nil +} From 83138e6b77c5c9620533125fcd6e38f7c877fd8e Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Tue, 24 Jan 2023 16:01:31 +0100 Subject: [PATCH 02/15] pass kubernetes version to lbm reconciler --- cmd/yawol-controller/main.go | 36 +++++++++++-------- .../loadbalancermachine_controller.go | 1 + 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/cmd/yawol-controller/main.go b/cmd/yawol-controller/main.go index 5714c01a..f2cc7c37 100644 --- a/cmd/yawol-controller/main.go +++ b/cmd/yawol-controller/main.go @@ -9,6 +9,7 @@ import ( "github.com/stackitcloud/yawol/controllers/yawol-controller/loadbalancer" "github.com/stackitcloud/yawol/controllers/yawol-controller/loadbalancermachine" "github.com/stackitcloud/yawol/controllers/yawol-controller/loadbalancerset" + "github.com/stackitcloud/yawol/internal/helper/kubernetes" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. @@ -122,10 +123,11 @@ func main() { var loadBalancerMgr manager.Manager var loadBalancerSetMgr manager.Manager var loadBalancerMachineMgr manager.Manager + cfg := ctrl.GetConfigOrDie() // Controller 2 if lbController { - loadBalancerMgr, err = ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + loadBalancerMgr, err = ctrl.NewManager(cfg, ctrl.Options{ Scheme: scheme, MetricsBindAddress: metricsAddrLb, Port: 9443, @@ -168,7 +170,7 @@ func main() { // Controller 3 if lbSetController { - loadBalancerSetMgr, err = ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + loadBalancerSetMgr, err = ctrl.NewManager(cfg, ctrl.Options{ Scheme: scheme, MetricsBindAddress: metricsAddrLbs, Port: 9444, @@ -214,7 +216,12 @@ func main() { panic("could not read env " + EnvAPIEndpoint) } - loadBalancerMachineMgr, err = ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + kubernetesVersion, err := kubernetes.GetVersion(cfg) + if err != nil { + panic("unable to determine kubernetes server version: " + err.Error()) + } + + loadBalancerMachineMgr, err = ctrl.NewManager(cfg, ctrl.Options{ Scheme: scheme, MetricsBindAddress: metricsAddrLbm, Port: 9445, @@ -232,17 +239,18 @@ func main() { } if err = (&loadbalancermachine.LoadBalancerMachineReconciler{ - Client: loadBalancerMachineMgr.GetClient(), - WorkerCount: concurrentWorkersPerReconciler, - APIHost: loadBalancerMachineMgr.GetConfig().Host, - CACert: loadBalancerMachineMgr.GetConfig().CAData, - Log: ctrl.Log.WithName("controller").WithName("LoadBalancerMachine"), - Recorder: loadBalancerMachineMgr.GetEventRecorderFor("LoadBalancerMachine"), - RecorderLB: loadBalancerMachineMgr.GetEventRecorderFor("yawol-service"), - Scheme: loadBalancerMachineMgr.GetScheme(), - APIEndpoint: apiEndpoint, - Metrics: &helpermetrics.LoadBalancerMachineMetrics, - OpenstackTimeout: openstackTimeout, + Client: loadBalancerMachineMgr.GetClient(), + WorkerCount: concurrentWorkersPerReconciler, + APIHost: loadBalancerMachineMgr.GetConfig().Host, + CACert: loadBalancerMachineMgr.GetConfig().CAData, + Log: ctrl.Log.WithName("controller").WithName("LoadBalancerMachine"), + Recorder: loadBalancerMachineMgr.GetEventRecorderFor("LoadBalancerMachine"), + RecorderLB: loadBalancerMachineMgr.GetEventRecorderFor("yawol-service"), + Scheme: loadBalancerMachineMgr.GetScheme(), + APIEndpoint: apiEndpoint, + Metrics: &helpermetrics.LoadBalancerMachineMetrics, + OpenstackTimeout: openstackTimeout, + KubernetesVersion: *kubernetesVersion, }).SetupWithManager(loadBalancerMachineMgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "LoadBalancerMachine") os.Exit(1) diff --git a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go index f607a30a..09facf04 100644 --- a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go +++ b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go @@ -59,6 +59,7 @@ type LoadBalancerMachineReconciler struct { //nolint:revive // naming from kubeb getOsClientForIni os.GetOSClientFunc WorkerCount int OpenstackTimeout time.Duration + KubernetesVersion kubernetes.Version } // Reconcile Reconciles a LoadBalancerMachine From 51abe4676efef49b9c6959ff917020ab365dea2b Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Tue, 24 Jan 2023 16:02:37 +0100 Subject: [PATCH 03/15] create secret when k8s version is greater than 1.24 --- .../loadbalancermachine_controller.go | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go index 09facf04..74b869a4 100644 --- a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go +++ b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go @@ -38,8 +38,9 @@ import ( const ( // ServiceFinalizer Name of finalizer for controller4 - ServiceFinalizer = "yawol.stackit.cloud/controller4" - DefaultRequeueTime = 10 * time.Millisecond + ServiceFinalizer = "yawol.stackit.cloud/controller4" + DefaultRequeueTime = 10 * time.Millisecond + ServiceAccountNameAnnotation = "kubernetes.io/service-account.name" ) var ipv4Regex = `^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})` @@ -154,6 +155,12 @@ func (r *LoadBalancerMachineReconciler) Reconcile(ctx context.Context, req ctrl. return res, err } + if r.KubernetesVersion.Major >= 1 && r.KubernetesVersion.Minor >= 24 { + if err := r.reconcileSecret(ctx, loadBalancerMachine, sa); err != nil { + return res, err + } + } + // Reconcile Role for yawollet access if err := r.reconcileRole(ctx, loadBalancerMachine, loadbalancer); err != nil { return ctrl.Result{}, err @@ -255,6 +262,51 @@ func (r *LoadBalancerMachineReconciler) reconcileSA( return sa, nil } +func (r *LoadBalancerMachineReconciler) reconcileSecret( + ctx context.Context, + loadBalancerMachine *yawolv1beta1.LoadBalancerMachine, + sa v1.ServiceAccount, +) error { + r.Log.Info("Check Secret", "loadBalancerMachineName", loadBalancerMachine.Name) + + secret := v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: loadBalancerMachine.Name, + Namespace: loadBalancerMachine.Namespace, + }, + } + + updateSecret := func(s *v1.Secret) { + s.Annotations = map[string]string{ + ServiceAccountNameAnnotation: sa.Name, + } + s.Type = v1.SecretTypeServiceAccountToken + } + + err := r.Client.Get(ctx, client.ObjectKeyFromObject(&secret), &secret) + if errors2.IsNotFound(err) { + r.Log.Info("Create Secret", "loadBalancerMachineName", loadBalancerMachine.Name) + updateSecret(&secret) + return r.Client.Create(ctx, &secret) + } + + if err != nil { + // kubernetes error happened + return err + } + + v, ok := secret.Annotations[ServiceAccountNameAnnotation] + if ok && v == sa.Name && secret.Type == v1.SecretTypeServiceAccountToken { + // secret is valid + return nil + } + + // set correct sa reference + updateSecret(&secret) + r.Log.Info("Update Secret", "loadBalancerMachineName", loadBalancerMachine.Name) + return r.Client.Update(ctx, &secret) +} + func (r *LoadBalancerMachineReconciler) reconcileRole( ctx context.Context, loadBalancerMachine *yawolv1beta1.LoadBalancerMachine, From fea8c6a6b1485e7cb5e255d67c588a3fef1904af Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Tue, 24 Jan 2023 16:03:01 +0100 Subject: [PATCH 04/15] add tests for secret creation --- .../loadbalancermachine_controller_test.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller_test.go b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller_test.go index efc054be..c4ed7b26 100644 --- a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller_test.go +++ b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller_test.go @@ -100,16 +100,21 @@ var _ = Describe("load balancer machine", func() { Eventually(func(g Gomega) { var actualRole rbac.Role g.Expect(k8sClient.Get(ctx, lbmNN, &actualRole)).To(Succeed()) - - // TODO somehow the arrays are not equal even though they are g.Expect(len(actualRole.Rules)).To(Equal(len(getPolicyRules(lb, lbm)))) }, timeout, interval).Should(Succeed()) - By("checking sa secret") + By("checking service account") Eventually(func(g Gomega) { g.Expect(k8sClient.Get(ctx, lbmNN, &v1.ServiceAccount{})).To(Succeed()) }, timeout, interval).Should(Succeed()) + By("checking secret") + Eventually(func(g Gomega) { + secret := &v1.Secret{} + g.Expect(k8sClient.Get(ctx, lbmNN, secret)).To(Succeed()) + g.Expect(secret.Annotations).To(HaveKeyWithValue(ServiceAccountNameAnnotation, lbmNN.Name)) + }, timeout, interval).Should(Succeed()) + By("checking rolebinding") Eventually(func(g Gomega) { var roleBinding rbac.RoleBinding From 50a9acca1d56a4421408d7a536e9650dfb371fea Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Tue, 24 Jan 2023 16:03:33 +0100 Subject: [PATCH 05/15] simplify getting service account --- .../loadbalancermachine/loadbalancermachine_controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go index 74b869a4..852496de 100644 --- a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go +++ b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go @@ -238,7 +238,7 @@ func (r *LoadBalancerMachineReconciler) reconcileSA( }, } - err := r.Client.Get(ctx, client.ObjectKey{Name: sa.Name, Namespace: sa.Namespace}, &sa) + err := r.Client.Get(ctx, client.ObjectKeyFromObject(&sa), &sa) if err != nil { if errors2.IsNotFound(err) { if err = r.Client.Create(ctx, &sa); err != nil { From c61eeae1b867cfccbc2e1394de72bd407b03ec79 Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Wed, 25 Jan 2023 11:32:46 +0100 Subject: [PATCH 06/15] save secretname into lbm status Signed-off-by: Felix Breuer --- api/v1beta1/loadbalancermachine_types.go | 3 + api/v1beta1/zz_generated.deepcopy.go | 5 ++ ...ol.stackit.cloud_loadbalancermachines.yaml | 4 ++ .../loadbalancermachine_controller.go | 55 ++++++++++++++++++- .../loadbalancermachine_controller_test.go | 13 +++++ internal/helper/errors.go | 1 + 6 files changed, 78 insertions(+), 3 deletions(-) diff --git a/api/v1beta1/loadbalancermachine_types.go b/api/v1beta1/loadbalancermachine_types.go index 18eccda8..e2e3a36c 100644 --- a/api/v1beta1/loadbalancermachine_types.go +++ b/api/v1beta1/loadbalancermachine_types.go @@ -85,6 +85,9 @@ type LoadBalancerMachineStatus struct { // ServiceAccountName contains the namespacedName from the ServiceAccount for a LoadBalancerMachine. // +optional ServiceAccountName *string `json:"serviceAccountName,omitempty"` + // SecretName contains the namespacedName from the Secret which belongs to the Serviceaccount. + // +optional + SecretName *string `json:"secretName,omitempty"` // RoleName contains the namespacedName from the Role for a LoadBalancerMachine. // +optional RoleName *string `json:"roleName,omitempty"` diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 007839cd..d55812fd 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -344,6 +344,11 @@ func (in *LoadBalancerMachineStatus) DeepCopyInto(out *LoadBalancerMachineStatus *out = new(string) **out = **in } + if in.SecretName != nil { + in, out := &in.SecretName, &out.SecretName + *out = new(string) + **out = **in + } if in.RoleName != nil { in, out := &in.RoleName, &out.RoleName *out = new(string) diff --git a/charts/yawol-controller/crds/yawol.stackit.cloud_loadbalancermachines.yaml b/charts/yawol-controller/crds/yawol.stackit.cloud_loadbalancermachines.yaml index 55becdb6..8ffff0d5 100644 --- a/charts/yawol-controller/crds/yawol.stackit.cloud_loadbalancermachines.yaml +++ b/charts/yawol-controller/crds/yawol.stackit.cloud_loadbalancermachines.yaml @@ -300,6 +300,10 @@ spec: description: RoleName contains the namespacedName from the Role for a LoadBalancerMachine. type: string + secretName: + description: SecretName contains the namespacedName from the Secret + which belongs to the Serviceaccount. + type: string serverID: description: ServerID contains the openstack server ID for a LoadBalancerMachine. type: string diff --git a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go index 852496de..f0c9b949 100644 --- a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go +++ b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go @@ -159,6 +159,13 @@ func (r *LoadBalancerMachineReconciler) Reconcile(ctx context.Context, req ctrl. if err := r.reconcileSecret(ctx, loadBalancerMachine, sa); err != nil { return res, err } + } else { + // save pre 1.24 created secret into status + if loadBalancerMachine.Status.SecretName == nil && len(sa.Secrets) > 0 { + if err := r.patchSecretNameStatus(ctx, loadBalancerMachine, &sa); err != nil { + return ctrl.Result{}, err + } + } } // Reconcile Role for yawollet access @@ -276,6 +283,17 @@ func (r *LoadBalancerMachineReconciler) reconcileSecret( }, } + // use secret referenced in status if possible + if loadBalancerMachine.Status.SecretName != nil { + splittedNN := strings.Split(*loadBalancerMachine.Status.SecretName, string(types.Separator)) + if len(splittedNN) != 2 { + return helper.ErrSecretNameSplit + } + + secret.Name = splittedNN[0] + secret.Namespace = splittedNN[1] + } + updateSecret := func(s *v1.Secret) { s.Annotations = map[string]string{ ServiceAccountNameAnnotation: sa.Name, @@ -287,11 +305,19 @@ func (r *LoadBalancerMachineReconciler) reconcileSecret( if errors2.IsNotFound(err) { r.Log.Info("Create Secret", "loadBalancerMachineName", loadBalancerMachine.Name) updateSecret(&secret) - return r.Client.Create(ctx, &secret) + if err := r.Client.Create(ctx, &secret); err != nil { + return err + } + + if err := r.patchSecretNameStatus(ctx, loadBalancerMachine, &sa); err != nil { + return err + } + + return nil } if err != nil { - // kubernetes error happened + // kubernetes error return err } @@ -304,7 +330,15 @@ func (r *LoadBalancerMachineReconciler) reconcileSecret( // set correct sa reference updateSecret(&secret) r.Log.Info("Update Secret", "loadBalancerMachineName", loadBalancerMachine.Name) - return r.Client.Update(ctx, &secret) + if err := r.Client.Update(ctx, &secret); err != nil { + return err + } + + if err := r.patchSecretNameStatus(ctx, loadBalancerMachine, &sa); err != nil { + return err + } + + return nil } func (r *LoadBalancerMachineReconciler) reconcileRole( @@ -982,6 +1016,21 @@ func (r *LoadBalancerMachineReconciler) deleteRole( return helper.RemoveFromLBMStatus(ctx, r.Client.Status(), lbm, "roleName") } +func (r *LoadBalancerMachineReconciler) patchSecretNameStatus( + ctx context.Context, + lbm *yawolv1beta1.LoadBalancerMachine, + sa *v1.ServiceAccount, +) error { + namespacedName := types.NamespacedName{ + Name: sa.Secrets[0].Name, + Namespace: sa.Secrets[0].Namespace, + }.String() + + return helper.PatchLBMStatus(ctx, r.Client.Status(), lbm, yawolv1beta1.LoadBalancerMachineStatus{ + SecretName: &namespacedName, + }) +} + func (r *LoadBalancerMachineReconciler) waitForServerStatus( ctx context.Context, serverClient os.ServerClient, diff --git a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller_test.go b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller_test.go index c4ed7b26..c6616ded 100644 --- a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller_test.go +++ b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller_test.go @@ -129,6 +129,19 @@ var _ = Describe("load balancer machine", func() { }, timeout, interval).Should(Succeed()) }) + It("should update lbm status", func() { + lbmNN := runtimeClient.ObjectKeyFromObject(lbm) + + By("checking that the rbac role gets created") + Eventually(func(g Gomega) { + var updatedLBM LBM + g.Expect(k8sClient.Get(ctx, lbmNN, &updatedLBM)).To(Succeed()) + g.Expect(updatedLBM.Status.SecretName).ToNot(BeNil()) + g.Expect(updatedLBM.Status.ServiceAccountName).ToNot(BeNil()) + g.Expect(updatedLBM.Status.RoleName).ToNot(BeNil()) + }, timeout, interval).Should(Succeed()) + }) + It("should create openstack resources", func() { lbmNN := runtimeClient.ObjectKeyFromObject(lbm) diff --git a/internal/helper/errors.go b/internal/helper/errors.go index b98f5fb5..da811da2 100644 --- a/internal/helper/errors.go +++ b/internal/helper/errors.go @@ -66,4 +66,5 @@ var ( ErrListingChildLBMs = errors.New("unable to list child loadbalancerMachines") ErrUnsupportedProtocol = errors.New("unsupported protocol used (TCP and UDP is supported)") ErrProjectIsImmutable = errors.New("project id is immutable, cant be changed after initial creation") + ErrSecretNameSplit = errors.New("unable to decode SecretName in LoadBalancerMachine.Status") ) From 467023f2dc69fe88e7714b507c9b44d6cee2d545 Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Wed, 25 Jan 2023 15:53:33 +0100 Subject: [PATCH 07/15] set correct k8s version in tests and fix secretname in status Signed-off-by: Felix Breuer --- .../loadbalancermachine_controller.go | 119 ++++++++++-------- .../loadbalancermachine/suite_test.go | 16 +-- internal/helper/errors.go | 1 - internal/helper/kubernetes/namespacedname.go | 22 ++++ 4 files changed, 98 insertions(+), 60 deletions(-) create mode 100644 internal/helper/kubernetes/namespacedname.go diff --git a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go index f0c9b949..571019f1 100644 --- a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go +++ b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go @@ -162,7 +162,16 @@ func (r *LoadBalancerMachineReconciler) Reconcile(ctx context.Context, req ctrl. } else { // save pre 1.24 created secret into status if loadBalancerMachine.Status.SecretName == nil && len(sa.Secrets) > 0 { - if err := r.patchSecretNameStatus(ctx, loadBalancerMachine, &sa); err != nil { + namespacedName := types.NamespacedName{ + Name: sa.Secrets[0].Name, + // the referenced secret has no namespace + // since it is the same as the service account + Namespace: sa.Namespace, + }.String() + + if err := helper.PatchLBMStatus(ctx, r.Client.Status(), loadBalancerMachine, yawolv1beta1.LoadBalancerMachineStatus{ + SecretName: &namespacedName, + }); err != nil { return ctrl.Result{}, err } } @@ -198,7 +207,7 @@ func (r *LoadBalancerMachineReconciler) Reconcile(ctx context.Context, req ctrl. return ctrl.Result{}, err } - if err := r.reconcileServer(ctx, osClient, loadbalancer, loadBalancerMachine, sa, vip); err != nil { + if err := r.reconcileServer(ctx, osClient, loadbalancer, loadBalancerMachine, vip); err != nil { return ctrl.Result{}, err } @@ -269,13 +278,11 @@ func (r *LoadBalancerMachineReconciler) reconcileSA( return sa, nil } -func (r *LoadBalancerMachineReconciler) reconcileSecret( +func (r *LoadBalancerMachineReconciler) createOrUpdateSecret( ctx context.Context, loadBalancerMachine *yawolv1beta1.LoadBalancerMachine, sa v1.ServiceAccount, -) error { - r.Log.Info("Check Secret", "loadBalancerMachineName", loadBalancerMachine.Name) - +) (*v1.Secret, error) { secret := v1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: loadBalancerMachine.Name, @@ -285,13 +292,13 @@ func (r *LoadBalancerMachineReconciler) reconcileSecret( // use secret referenced in status if possible if loadBalancerMachine.Status.SecretName != nil { - splittedNN := strings.Split(*loadBalancerMachine.Status.SecretName, string(types.Separator)) - if len(splittedNN) != 2 { - return helper.ErrSecretNameSplit + nn, err := kubernetes.ToNamespacedName(*loadBalancerMachine.Status.SecretName) + if err != nil { + return nil, err } - secret.Name = splittedNN[0] - secret.Namespace = splittedNN[1] + secret.Name = nn.Name + secret.Namespace = nn.Namespace } updateSecret := func(s *v1.Secret) { @@ -302,43 +309,64 @@ func (r *LoadBalancerMachineReconciler) reconcileSecret( } err := r.Client.Get(ctx, client.ObjectKeyFromObject(&secret), &secret) + if client.IgnoreNotFound(err) != nil { + // kubernetes error + return nil, err + } + if errors2.IsNotFound(err) { + // create secret r.Log.Info("Create Secret", "loadBalancerMachineName", loadBalancerMachine.Name) updateSecret(&secret) if err := r.Client.Create(ctx, &secret); err != nil { - return err + return nil, err } - if err := r.patchSecretNameStatus(ctx, loadBalancerMachine, &sa); err != nil { - return err - } - - return nil - } - - if err != nil { - // kubernetes error - return err + return &secret, nil } v, ok := secret.Annotations[ServiceAccountNameAnnotation] if ok && v == sa.Name && secret.Type == v1.SecretTypeServiceAccountToken { // secret is valid - return nil + return &secret, nil } - // set correct sa reference + // update secret updateSecret(&secret) r.Log.Info("Update Secret", "loadBalancerMachineName", loadBalancerMachine.Name) if err := r.Client.Update(ctx, &secret); err != nil { - return err + return nil, err } - if err := r.patchSecretNameStatus(ctx, loadBalancerMachine, &sa); err != nil { + return &secret, nil +} + +func (r *LoadBalancerMachineReconciler) reconcileSecret( + ctx context.Context, + loadBalancerMachine *yawolv1beta1.LoadBalancerMachine, + sa v1.ServiceAccount, +) error { + r.Log.Info("Check Secret", "loadBalancerMachineName", loadBalancerMachine.Name) + + secret, err := r.createOrUpdateSecret(ctx, loadBalancerMachine, sa) + if err != nil { return err } - return nil + namespacedNameString := types.NamespacedName{ + Name: secret.Name, + Namespace: secret.Namespace, + }.String() + + if loadBalancerMachine.Status.SecretName != nil && *loadBalancerMachine.Status.SecretName != namespacedNameString { + // status already updated + return nil + } + + // patch secretName in status + return helper.PatchLBMStatus(ctx, r.Client.Status(), loadBalancerMachine, yawolv1beta1.LoadBalancerMachineStatus{ + SecretName: &namespacedNameString, + }) } func (r *LoadBalancerMachineReconciler) reconcileRole( @@ -655,7 +683,6 @@ func (r *LoadBalancerMachineReconciler) reconcileServer( osClient os.Client, loadbalancer *yawolv1beta1.LoadBalancer, loadBalancerMachine *yawolv1beta1.LoadBalancerMachine, - serviceAccount v1.ServiceAccount, vip string, ) error { var srvClient os.ServerClient @@ -668,7 +695,7 @@ func (r *LoadBalancerMachineReconciler) reconcileServer( // get kubeconfig which will be passed to VM user-data for yawollet access var kubeconfig string - if kubeconfig, err = r.getKubeConfigForServiceAccount(ctx, loadBalancerMachine.Namespace, serviceAccount); err != nil { + if kubeconfig, err = r.getKubeConfigForServiceAccount(ctx, loadBalancerMachine.Status.SecretName); err != nil { return err } @@ -1016,21 +1043,6 @@ func (r *LoadBalancerMachineReconciler) deleteRole( return helper.RemoveFromLBMStatus(ctx, r.Client.Status(), lbm, "roleName") } -func (r *LoadBalancerMachineReconciler) patchSecretNameStatus( - ctx context.Context, - lbm *yawolv1beta1.LoadBalancerMachine, - sa *v1.ServiceAccount, -) error { - namespacedName := types.NamespacedName{ - Name: sa.Secrets[0].Name, - Namespace: sa.Secrets[0].Namespace, - }.String() - - return helper.PatchLBMStatus(ctx, r.Client.Status(), lbm, yawolv1beta1.LoadBalancerMachineStatus{ - SecretName: &namespacedName, - }) -} - func (r *LoadBalancerMachineReconciler) waitForServerStatus( ctx context.Context, serverClient os.ServerClient, @@ -1069,17 +1081,20 @@ func (r *LoadBalancerMachineReconciler) waitForServerStatus( func (r *LoadBalancerMachineReconciler) getKubeConfigForServiceAccount( ctx context.Context, - namespace string, - sa v1.ServiceAccount, + namespacedName *string, ) (string, error) { - if len(sa.Secrets) < 1 { - return "", fmt.Errorf("%w for serviceAccount %s", helper.ErrSecretNotFound, sa.Name) + if namespacedName == nil { + return "", fmt.Errorf("%w NamespacedName is nil", helper.ErrSecretNotFound) } sec := v1.Secret{} - var err error - if err = r.Client.Get(ctx, types.NamespacedName{Name: sa.Secrets[0].Name, Namespace: namespace}, &sec); err != nil { - return "", fmt.Errorf("%w cloud not getting %s", helper.ErrSecretNotFound, sec.Name) + nn, err := kubernetes.ToNamespacedName(*namespacedName) + if err != nil { + return "", err + } + + if err := r.Client.Get(ctx, nn, &sec); err != nil { + return "", fmt.Errorf("%w could not get %s", helper.ErrSecretNotFound, nn.String()) } var token, ca []byte @@ -1107,7 +1122,7 @@ func (r *LoadBalancerMachineReconciler) getKubeConfigForServiceAccount( Contexts: map[string]*api.Context{"context": { Cluster: "default-cluster", AuthInfo: "user", - Namespace: namespace, + Namespace: nn.Namespace, }}, CurrentContext: "context", } diff --git a/controllers/yawol-controller/loadbalancermachine/suite_test.go b/controllers/yawol-controller/loadbalancermachine/suite_test.go index 7b02e313..a70edab9 100644 --- a/controllers/yawol-controller/loadbalancermachine/suite_test.go +++ b/controllers/yawol-controller/loadbalancermachine/suite_test.go @@ -11,6 +11,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" yawolv1beta1 "github.com/stackitcloud/yawol/api/v1beta1" + "github.com/stackitcloud/yawol/internal/helper/kubernetes" helpermetrics "github.com/stackitcloud/yawol/internal/metrics" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" @@ -96,13 +97,14 @@ var _ = BeforeSuite(func() { Expect(k8sClient.Create(context.Background(), &secret)).Should(Succeed()) loadBalancerMachineReconciler = &LoadBalancerMachineReconciler{ - APIEndpoint: "https://lala.com", - Client: k8sManager.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("LoadBalancerMachine"), - Scheme: k8sManager.GetScheme(), - Recorder: k8sManager.GetEventRecorderFor("LoadBalancerMachine"), - RecorderLB: k8sManager.GetEventRecorderFor("yawol-service"), - Metrics: &helpermetrics.LoadBalancerMachineMetrics, + APIEndpoint: "https://lala.com", + Client: k8sManager.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("LoadBalancerMachine"), + Scheme: k8sManager.GetScheme(), + Recorder: k8sManager.GetEventRecorderFor("LoadBalancerMachine"), + RecorderLB: k8sManager.GetEventRecorderFor("yawol-service"), + Metrics: &helpermetrics.LoadBalancerMachineMetrics, + KubernetesVersion: kubernetes.Version{Major: 1, Minor: 24}, } err = loadBalancerMachineReconciler.SetupWithManager(k8sManager) diff --git a/internal/helper/errors.go b/internal/helper/errors.go index da811da2..b98f5fb5 100644 --- a/internal/helper/errors.go +++ b/internal/helper/errors.go @@ -66,5 +66,4 @@ var ( ErrListingChildLBMs = errors.New("unable to list child loadbalancerMachines") ErrUnsupportedProtocol = errors.New("unsupported protocol used (TCP and UDP is supported)") ErrProjectIsImmutable = errors.New("project id is immutable, cant be changed after initial creation") - ErrSecretNameSplit = errors.New("unable to decode SecretName in LoadBalancerMachine.Status") ) diff --git a/internal/helper/kubernetes/namespacedname.go b/internal/helper/kubernetes/namespacedname.go new file mode 100644 index 00000000..ea1d03b6 --- /dev/null +++ b/internal/helper/kubernetes/namespacedname.go @@ -0,0 +1,22 @@ +package kubernetes + +import ( + "errors" + "strings" + + "k8s.io/apimachinery/pkg/types" +) + +var ErrNamespacedNameSplit = errors.New("unable to decode string into NamespacedName") + +func ToNamespacedName(nnString string) (types.NamespacedName, error) { + splittedNN := strings.Split(nnString, string(types.Separator)) + if len(splittedNN) != 2 { + return types.NamespacedName{}, ErrNamespacedNameSplit + } + + return types.NamespacedName{ + Namespace: splittedNN[0], + Name: splittedNN[1], + }, nil +} From 365f6b54dac2e12e4f4d2e1e2f9c8faf58eb8689 Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Fri, 27 Jan 2023 10:18:03 +0100 Subject: [PATCH 08/15] Update controllers/yawol-controller/loadbalancermachine/suite_test.go Co-authored-by: Maximilian Geberl <48486938+dergeberl@users.noreply.github.com> Signed-off-by: Felix Breuer --- controllers/yawol-controller/loadbalancermachine/suite_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/yawol-controller/loadbalancermachine/suite_test.go b/controllers/yawol-controller/loadbalancermachine/suite_test.go index a70edab9..4782e833 100644 --- a/controllers/yawol-controller/loadbalancermachine/suite_test.go +++ b/controllers/yawol-controller/loadbalancermachine/suite_test.go @@ -97,7 +97,7 @@ var _ = BeforeSuite(func() { Expect(k8sClient.Create(context.Background(), &secret)).Should(Succeed()) loadBalancerMachineReconciler = &LoadBalancerMachineReconciler{ - APIEndpoint: "https://lala.com", + APIEndpoint: "https://example.com", Client: k8sManager.GetClient(), Log: ctrl.Log.WithName("controllers").WithName("LoadBalancerMachine"), Scheme: k8sManager.GetScheme(), From 1249373c88801d965e7be06384b33464bb9fd242 Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Mon, 30 Jan 2023 10:32:33 +0100 Subject: [PATCH 09/15] Update internal/helper/kubernetes/version.go Co-authored-by: Maximilian Geberl <48486938+dergeberl@users.noreply.github.com> Signed-off-by: Felix Breuer --- internal/helper/kubernetes/version.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/helper/kubernetes/version.go b/internal/helper/kubernetes/version.go index 0f2b748f..42b3b63c 100644 --- a/internal/helper/kubernetes/version.go +++ b/internal/helper/kubernetes/version.go @@ -13,7 +13,10 @@ type Version struct { } func GetVersion(cfg *rest.Config) (*Version, error) { - client := discovery.NewDiscoveryClientForConfigOrDie(cfg) + client, err := discovery.NewDiscoveryClientForConfig(cfg) + err != nil { + return nil, err + } version, err := client.ServerVersion() if err != nil { return nil, err From 8ac35035c260dee38218c084b0b260372d58274f Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Mon, 30 Jan 2023 10:32:43 +0100 Subject: [PATCH 10/15] Update api/v1beta1/loadbalancermachine_types.go Co-authored-by: Maximilian Geberl <48486938+dergeberl@users.noreply.github.com> Signed-off-by: Felix Breuer --- api/v1beta1/loadbalancermachine_types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1beta1/loadbalancermachine_types.go b/api/v1beta1/loadbalancermachine_types.go index e2e3a36c..7dae5d20 100644 --- a/api/v1beta1/loadbalancermachine_types.go +++ b/api/v1beta1/loadbalancermachine_types.go @@ -87,7 +87,7 @@ type LoadBalancerMachineStatus struct { ServiceAccountName *string `json:"serviceAccountName,omitempty"` // SecretName contains the namespacedName from the Secret which belongs to the Serviceaccount. // +optional - SecretName *string `json:"secretName,omitempty"` + ServiceAccountSecretName *string `json:"serviceAccountSecretName,omitempty"` // RoleName contains the namespacedName from the Role for a LoadBalancerMachine. // +optional RoleName *string `json:"roleName,omitempty"` From ba9bf7d3ed7788ba1765138023ee4e91a2171a72 Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Mon, 30 Jan 2023 11:07:00 +0100 Subject: [PATCH 11/15] rename secretName and use kubernetes version in tests Signed-off-by: Felix Breuer --- api/v1beta1/zz_generated.deepcopy.go | 4 ++-- .../yawol.stackit.cloud_loadbalancermachines.yaml | 8 ++++---- .../loadbalancermachine_controller.go | 15 ++++++++------- .../loadbalancermachine_controller_test.go | 2 +- .../loadbalancermachine/suite_test.go | 5 ++++- internal/helper/kubernetes/version.go | 3 ++- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index d55812fd..4530875a 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -344,8 +344,8 @@ func (in *LoadBalancerMachineStatus) DeepCopyInto(out *LoadBalancerMachineStatus *out = new(string) **out = **in } - if in.SecretName != nil { - in, out := &in.SecretName, &out.SecretName + if in.ServiceAccountSecretName != nil { + in, out := &in.ServiceAccountSecretName, &out.ServiceAccountSecretName *out = new(string) **out = **in } diff --git a/charts/yawol-controller/crds/yawol.stackit.cloud_loadbalancermachines.yaml b/charts/yawol-controller/crds/yawol.stackit.cloud_loadbalancermachines.yaml index 8ffff0d5..9ebbef65 100644 --- a/charts/yawol-controller/crds/yawol.stackit.cloud_loadbalancermachines.yaml +++ b/charts/yawol-controller/crds/yawol.stackit.cloud_loadbalancermachines.yaml @@ -300,10 +300,6 @@ spec: description: RoleName contains the namespacedName from the Role for a LoadBalancerMachine. type: string - secretName: - description: SecretName contains the namespacedName from the Secret - which belongs to the Serviceaccount. - type: string serverID: description: ServerID contains the openstack server ID for a LoadBalancerMachine. type: string @@ -311,6 +307,10 @@ spec: description: ServiceAccountName contains the namespacedName from the ServiceAccount for a LoadBalancerMachine. type: string + serviceAccountSecretName: + description: SecretName contains the namespacedName from the Secret + which belongs to the Serviceaccount. + type: string type: object type: object served: true diff --git a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go index 571019f1..d61147e5 100644 --- a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go +++ b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go @@ -161,7 +161,7 @@ func (r *LoadBalancerMachineReconciler) Reconcile(ctx context.Context, req ctrl. } } else { // save pre 1.24 created secret into status - if loadBalancerMachine.Status.SecretName == nil && len(sa.Secrets) > 0 { + if loadBalancerMachine.Status.ServiceAccountSecretName == nil && len(sa.Secrets) > 0 { namespacedName := types.NamespacedName{ Name: sa.Secrets[0].Name, // the referenced secret has no namespace @@ -170,7 +170,7 @@ func (r *LoadBalancerMachineReconciler) Reconcile(ctx context.Context, req ctrl. }.String() if err := helper.PatchLBMStatus(ctx, r.Client.Status(), loadBalancerMachine, yawolv1beta1.LoadBalancerMachineStatus{ - SecretName: &namespacedName, + ServiceAccountSecretName: &namespacedName, }); err != nil { return ctrl.Result{}, err } @@ -291,8 +291,8 @@ func (r *LoadBalancerMachineReconciler) createOrUpdateSecret( } // use secret referenced in status if possible - if loadBalancerMachine.Status.SecretName != nil { - nn, err := kubernetes.ToNamespacedName(*loadBalancerMachine.Status.SecretName) + if loadBalancerMachine.Status.ServiceAccountSecretName != nil { + nn, err := kubernetes.ToNamespacedName(*loadBalancerMachine.Status.ServiceAccountSecretName) if err != nil { return nil, err } @@ -358,14 +358,15 @@ func (r *LoadBalancerMachineReconciler) reconcileSecret( Namespace: secret.Namespace, }.String() - if loadBalancerMachine.Status.SecretName != nil && *loadBalancerMachine.Status.SecretName != namespacedNameString { + if loadBalancerMachine.Status.ServiceAccountSecretName != nil && + *loadBalancerMachine.Status.ServiceAccountSecretName != namespacedNameString { // status already updated return nil } // patch secretName in status return helper.PatchLBMStatus(ctx, r.Client.Status(), loadBalancerMachine, yawolv1beta1.LoadBalancerMachineStatus{ - SecretName: &namespacedNameString, + ServiceAccountSecretName: &namespacedNameString, }) } @@ -695,7 +696,7 @@ func (r *LoadBalancerMachineReconciler) reconcileServer( // get kubeconfig which will be passed to VM user-data for yawollet access var kubeconfig string - if kubeconfig, err = r.getKubeConfigForServiceAccount(ctx, loadBalancerMachine.Status.SecretName); err != nil { + if kubeconfig, err = r.getKubeConfigForServiceAccount(ctx, loadBalancerMachine.Status.ServiceAccountSecretName); err != nil { return err } diff --git a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller_test.go b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller_test.go index c6616ded..0e950235 100644 --- a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller_test.go +++ b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller_test.go @@ -136,8 +136,8 @@ var _ = Describe("load balancer machine", func() { Eventually(func(g Gomega) { var updatedLBM LBM g.Expect(k8sClient.Get(ctx, lbmNN, &updatedLBM)).To(Succeed()) - g.Expect(updatedLBM.Status.SecretName).ToNot(BeNil()) g.Expect(updatedLBM.Status.ServiceAccountName).ToNot(BeNil()) + g.Expect(updatedLBM.Status.ServiceAccountSecretName).ToNot(BeNil()) g.Expect(updatedLBM.Status.RoleName).ToNot(BeNil()) }, timeout, interval).Should(Succeed()) }) diff --git a/controllers/yawol-controller/loadbalancermachine/suite_test.go b/controllers/yawol-controller/loadbalancermachine/suite_test.go index 4782e833..57f3aa12 100644 --- a/controllers/yawol-controller/loadbalancermachine/suite_test.go +++ b/controllers/yawol-controller/loadbalancermachine/suite_test.go @@ -96,6 +96,9 @@ var _ = BeforeSuite(func() { } Expect(k8sClient.Create(context.Background(), &secret)).Should(Succeed()) + kubernetesVersion, err := kubernetes.GetVersion(cfg) + Expect(err).ToNot(HaveOccurred()) + loadBalancerMachineReconciler = &LoadBalancerMachineReconciler{ APIEndpoint: "https://example.com", Client: k8sManager.GetClient(), @@ -104,7 +107,7 @@ var _ = BeforeSuite(func() { Recorder: k8sManager.GetEventRecorderFor("LoadBalancerMachine"), RecorderLB: k8sManager.GetEventRecorderFor("yawol-service"), Metrics: &helpermetrics.LoadBalancerMachineMetrics, - KubernetesVersion: kubernetes.Version{Major: 1, Minor: 24}, + KubernetesVersion: *kubernetesVersion, } err = loadBalancerMachineReconciler.SetupWithManager(k8sManager) diff --git a/internal/helper/kubernetes/version.go b/internal/helper/kubernetes/version.go index 42b3b63c..46f47c1b 100644 --- a/internal/helper/kubernetes/version.go +++ b/internal/helper/kubernetes/version.go @@ -14,9 +14,10 @@ type Version struct { func GetVersion(cfg *rest.Config) (*Version, error) { client, err := discovery.NewDiscoveryClientForConfig(cfg) - err != nil { + if err != nil { return nil, err } + version, err := client.ServerVersion() if err != nil { return nil, err From ea6814b179392b224813f96ebd4dba02fa0c3cee Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Mon, 30 Jan 2023 16:14:11 +0100 Subject: [PATCH 12/15] add rbac rules to allow modifications to secrets Signed-off-by: Felix Breuer --- .../templates/rbac-yawol-controller.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/charts/yawol-controller/templates/rbac-yawol-controller.yaml b/charts/yawol-controller/templates/rbac-yawol-controller.yaml index 3a148785..1e0cc08e 100644 --- a/charts/yawol-controller/templates/rbac-yawol-controller.yaml +++ b/charts/yawol-controller/templates/rbac-yawol-controller.yaml @@ -17,9 +17,13 @@ rules: resources: - "secrets" verbs: - - "get" - - "list" - - "watch" + - get + - list + - watch + - create + - update + - patch + - delete - apiGroups: [""] resources: - "serviceaccounts" From f872694c18bdcbdc9cfff4aeed82fc9264a76c3d Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Tue, 31 Jan 2023 16:39:06 +0100 Subject: [PATCH 13/15] restructure creation of serviceaccount secret Signed-off-by: Felix Breuer --- cmd/yawol-controller/main.go | 31 ++--- .../loadbalancermachine_controller.go | 128 ++++++------------ .../loadbalancermachine/suite_test.go | 20 +-- internal/helper/kubernetes/version.go | 8 +- 4 files changed, 69 insertions(+), 118 deletions(-) diff --git a/cmd/yawol-controller/main.go b/cmd/yawol-controller/main.go index f2cc7c37..54aad4cf 100644 --- a/cmd/yawol-controller/main.go +++ b/cmd/yawol-controller/main.go @@ -9,7 +9,6 @@ import ( "github.com/stackitcloud/yawol/controllers/yawol-controller/loadbalancer" "github.com/stackitcloud/yawol/controllers/yawol-controller/loadbalancermachine" "github.com/stackitcloud/yawol/controllers/yawol-controller/loadbalancerset" - "github.com/stackitcloud/yawol/internal/helper/kubernetes" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. @@ -20,6 +19,7 @@ import ( helpermetrics "github.com/stackitcloud/yawol/internal/metrics" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + discovery "k8s.io/client-go/discovery" clientgoscheme "k8s.io/client-go/kubernetes/scheme" ctrl "sigs.k8s.io/controller-runtime" @@ -216,10 +216,7 @@ func main() { panic("could not read env " + EnvAPIEndpoint) } - kubernetesVersion, err := kubernetes.GetVersion(cfg) - if err != nil { - panic("unable to determine kubernetes server version: " + err.Error()) - } + discoveryClient := discovery.NewDiscoveryClientForConfigOrDie(cfg) loadBalancerMachineMgr, err = ctrl.NewManager(cfg, ctrl.Options{ Scheme: scheme, @@ -239,18 +236,18 @@ func main() { } if err = (&loadbalancermachine.LoadBalancerMachineReconciler{ - Client: loadBalancerMachineMgr.GetClient(), - WorkerCount: concurrentWorkersPerReconciler, - APIHost: loadBalancerMachineMgr.GetConfig().Host, - CACert: loadBalancerMachineMgr.GetConfig().CAData, - Log: ctrl.Log.WithName("controller").WithName("LoadBalancerMachine"), - Recorder: loadBalancerMachineMgr.GetEventRecorderFor("LoadBalancerMachine"), - RecorderLB: loadBalancerMachineMgr.GetEventRecorderFor("yawol-service"), - Scheme: loadBalancerMachineMgr.GetScheme(), - APIEndpoint: apiEndpoint, - Metrics: &helpermetrics.LoadBalancerMachineMetrics, - OpenstackTimeout: openstackTimeout, - KubernetesVersion: *kubernetesVersion, + Client: loadBalancerMachineMgr.GetClient(), + WorkerCount: concurrentWorkersPerReconciler, + APIHost: loadBalancerMachineMgr.GetConfig().Host, + CACert: loadBalancerMachineMgr.GetConfig().CAData, + Log: ctrl.Log.WithName("controller").WithName("LoadBalancerMachine"), + Recorder: loadBalancerMachineMgr.GetEventRecorderFor("LoadBalancerMachine"), + RecorderLB: loadBalancerMachineMgr.GetEventRecorderFor("yawol-service"), + Scheme: loadBalancerMachineMgr.GetScheme(), + APIEndpoint: apiEndpoint, + Metrics: &helpermetrics.LoadBalancerMachineMetrics, + OpenstackTimeout: openstackTimeout, + DiscoveryClient: discoveryClient, }).SetupWithManager(loadBalancerMachineMgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "LoadBalancerMachine") os.Exit(1) diff --git a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go index d61147e5..1420280d 100644 --- a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go +++ b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go @@ -27,6 +27,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/discovery" "k8s.io/client-go/tools/clientcmd/api" "k8s.io/client-go/tools/clientcmd/api/latest" "k8s.io/client-go/tools/record" @@ -60,7 +61,7 @@ type LoadBalancerMachineReconciler struct { //nolint:revive // naming from kubeb getOsClientForIni os.GetOSClientFunc WorkerCount int OpenstackTimeout time.Duration - KubernetesVersion kubernetes.Version + DiscoveryClient *discovery.DiscoveryClient } // Reconcile Reconciles a LoadBalancerMachine @@ -155,26 +156,9 @@ func (r *LoadBalancerMachineReconciler) Reconcile(ctx context.Context, req ctrl. return res, err } - if r.KubernetesVersion.Major >= 1 && r.KubernetesVersion.Minor >= 24 { - if err := r.reconcileSecret(ctx, loadBalancerMachine, sa); err != nil { - return res, err - } - } else { - // save pre 1.24 created secret into status - if loadBalancerMachine.Status.ServiceAccountSecretName == nil && len(sa.Secrets) > 0 { - namespacedName := types.NamespacedName{ - Name: sa.Secrets[0].Name, - // the referenced secret has no namespace - // since it is the same as the service account - Namespace: sa.Namespace, - }.String() - - if err := helper.PatchLBMStatus(ctx, r.Client.Status(), loadBalancerMachine, yawolv1beta1.LoadBalancerMachineStatus{ - ServiceAccountSecretName: &namespacedName, - }); err != nil { - return ctrl.Result{}, err - } - } + // Reconcile ServiceAccountSecret for yawollet access + if err := r.reconcileSecret(ctx, loadBalancerMachine, sa); err != nil { + return res, err } // Reconcile Role for yawollet access @@ -278,78 +262,60 @@ func (r *LoadBalancerMachineReconciler) reconcileSA( return sa, nil } -func (r *LoadBalancerMachineReconciler) createOrUpdateSecret( +func (r *LoadBalancerMachineReconciler) reconcileSecret( ctx context.Context, loadBalancerMachine *yawolv1beta1.LoadBalancerMachine, sa v1.ServiceAccount, -) (*v1.Secret, error) { - secret := v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: loadBalancerMachine.Name, - Namespace: loadBalancerMachine.Namespace, - }, - } - - // use secret referenced in status if possible +) error { + r.Log.Info("Check Secret", "loadBalancerMachineName", loadBalancerMachine.Name) if loadBalancerMachine.Status.ServiceAccountSecretName != nil { - nn, err := kubernetes.ToNamespacedName(*loadBalancerMachine.Status.ServiceAccountSecretName) - if err != nil { - return nil, err - } - - secret.Name = nn.Name - secret.Namespace = nn.Namespace + // no need to check if the secret is still present + // on false secret, the machine will delete itself + return nil } - updateSecret := func(s *v1.Secret) { - s.Annotations = map[string]string{ - ServiceAccountNameAnnotation: sa.Name, - } - s.Type = v1.SecretTypeServiceAccountToken - } + // use pre 1.24 created secret + if len(sa.Secrets) > 0 { + r.Log.Info("Use Secret from ServiceAccount", "loadBalancerMachineName", loadBalancerMachine.Name) + namespacedName := types.NamespacedName{ + Name: sa.Secrets[0].Name, + // the referenced secret has no namespace + // since it is the same as the service account + Namespace: sa.Namespace, + }.String() - err := r.Client.Get(ctx, client.ObjectKeyFromObject(&secret), &secret) - if client.IgnoreNotFound(err) != nil { - // kubernetes error - return nil, err + // return since secret is already created + return helper.PatchLBMStatus(ctx, r.Client.Status(), loadBalancerMachine, yawolv1beta1.LoadBalancerMachineStatus{ + ServiceAccountSecretName: &namespacedName, + }) } - if errors2.IsNotFound(err) { - // create secret - r.Log.Info("Create Secret", "loadBalancerMachineName", loadBalancerMachine.Name) - updateSecret(&secret) - if err := r.Client.Create(ctx, &secret); err != nil { - return nil, err - } - - return &secret, nil + // check if kubernetes handles secret creation + version, err := kubernetes.GetVersion(r.DiscoveryClient) + if err != nil { + return err } - v, ok := secret.Annotations[ServiceAccountNameAnnotation] - if ok && v == sa.Name && secret.Type == v1.SecretTypeServiceAccountToken { - // secret is valid - return &secret, nil + if version.Major <= 1 && version.Minor < 24 { + // secret not created by kubernetes + // requeue until created + return helper.ErrSecretNotFound } - // update secret - updateSecret(&secret) - r.Log.Info("Update Secret", "loadBalancerMachineName", loadBalancerMachine.Name) - if err := r.Client.Update(ctx, &secret); err != nil { - return nil, err + r.Log.Info("Create Secret", "loadBalancerMachineName", loadBalancerMachine.Name) + // secret does not exist, create a new one + secret := v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: loadBalancerMachine.Name, + Namespace: loadBalancerMachine.Namespace, + Annotations: map[string]string{ + ServiceAccountNameAnnotation: sa.Name, + }, + }, + Type: v1.SecretTypeServiceAccountToken, } - return &secret, nil -} - -func (r *LoadBalancerMachineReconciler) reconcileSecret( - ctx context.Context, - loadBalancerMachine *yawolv1beta1.LoadBalancerMachine, - sa v1.ServiceAccount, -) error { - r.Log.Info("Check Secret", "loadBalancerMachineName", loadBalancerMachine.Name) - - secret, err := r.createOrUpdateSecret(ctx, loadBalancerMachine, sa) - if err != nil { + if err := r.Client.Create(ctx, &secret); err != nil { return err } @@ -358,12 +324,6 @@ func (r *LoadBalancerMachineReconciler) reconcileSecret( Namespace: secret.Namespace, }.String() - if loadBalancerMachine.Status.ServiceAccountSecretName != nil && - *loadBalancerMachine.Status.ServiceAccountSecretName != namespacedNameString { - // status already updated - return nil - } - // patch secretName in status return helper.PatchLBMStatus(ctx, r.Client.Status(), loadBalancerMachine, yawolv1beta1.LoadBalancerMachineStatus{ ServiceAccountSecretName: &namespacedNameString, diff --git a/controllers/yawol-controller/loadbalancermachine/suite_test.go b/controllers/yawol-controller/loadbalancermachine/suite_test.go index 57f3aa12..554cac98 100644 --- a/controllers/yawol-controller/loadbalancermachine/suite_test.go +++ b/controllers/yawol-controller/loadbalancermachine/suite_test.go @@ -11,8 +11,8 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" yawolv1beta1 "github.com/stackitcloud/yawol/api/v1beta1" - "github.com/stackitcloud/yawol/internal/helper/kubernetes" helpermetrics "github.com/stackitcloud/yawol/internal/metrics" + discovery "k8s.io/client-go/discovery" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" @@ -96,18 +96,18 @@ var _ = BeforeSuite(func() { } Expect(k8sClient.Create(context.Background(), &secret)).Should(Succeed()) - kubernetesVersion, err := kubernetes.GetVersion(cfg) + discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg) Expect(err).ToNot(HaveOccurred()) loadBalancerMachineReconciler = &LoadBalancerMachineReconciler{ - APIEndpoint: "https://example.com", - Client: k8sManager.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("LoadBalancerMachine"), - Scheme: k8sManager.GetScheme(), - Recorder: k8sManager.GetEventRecorderFor("LoadBalancerMachine"), - RecorderLB: k8sManager.GetEventRecorderFor("yawol-service"), - Metrics: &helpermetrics.LoadBalancerMachineMetrics, - KubernetesVersion: *kubernetesVersion, + APIEndpoint: "https://example.com", + Client: k8sManager.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("LoadBalancerMachine"), + Scheme: k8sManager.GetScheme(), + Recorder: k8sManager.GetEventRecorderFor("LoadBalancerMachine"), + RecorderLB: k8sManager.GetEventRecorderFor("yawol-service"), + Metrics: &helpermetrics.LoadBalancerMachineMetrics, + DiscoveryClient: discoveryClient, } err = loadBalancerMachineReconciler.SetupWithManager(k8sManager) diff --git a/internal/helper/kubernetes/version.go b/internal/helper/kubernetes/version.go index 46f47c1b..ac0957de 100644 --- a/internal/helper/kubernetes/version.go +++ b/internal/helper/kubernetes/version.go @@ -4,7 +4,6 @@ import ( "strconv" discovery "k8s.io/client-go/discovery" - "k8s.io/client-go/rest" ) type Version struct { @@ -12,12 +11,7 @@ type Version struct { Minor int } -func GetVersion(cfg *rest.Config) (*Version, error) { - client, err := discovery.NewDiscoveryClientForConfig(cfg) - if err != nil { - return nil, err - } - +func GetVersion(client *discovery.DiscoveryClient) (*Version, error) { version, err := client.ServerVersion() if err != nil { return nil, err From ead4004334a310b8f433afb751d451901a212b97 Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Wed, 1 Feb 2023 11:15:38 +0100 Subject: [PATCH 14/15] add version compare functions Signed-off-by: Felix Breuer --- .../loadbalancermachine_controller.go | 11 ++- internal/helper/kubernetes/suite_test.go | 14 ++++ internal/helper/kubernetes/version.go | 38 +++++++++ internal/helper/kubernetes/version_test.go | 81 +++++++++++++++++++ 4 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 internal/helper/kubernetes/suite_test.go create mode 100644 internal/helper/kubernetes/version_test.go diff --git a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go index 1420280d..86da9316 100644 --- a/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go +++ b/controllers/yawol-controller/loadbalancermachine/loadbalancermachine_controller.go @@ -296,7 +296,7 @@ func (r *LoadBalancerMachineReconciler) reconcileSecret( return err } - if version.Major <= 1 && version.Minor < 24 { + if version.IsLower(&kubernetes.Version{Major: 1, Minor: 24}) { // secret not created by kubernetes // requeue until created return helper.ErrSecretNotFound @@ -315,10 +315,17 @@ func (r *LoadBalancerMachineReconciler) reconcileSecret( Type: v1.SecretTypeServiceAccountToken, } - if err := r.Client.Create(ctx, &secret); err != nil { + err = r.Client.Get(ctx, client.ObjectKeyFromObject(&secret), &v1.Secret{}) + if client.IgnoreNotFound(err) != nil { return err } + if errors2.IsNotFound(err) { + if err := r.Client.Create(ctx, &secret); err != nil { + return err + } + } + namespacedNameString := types.NamespacedName{ Name: secret.Name, Namespace: secret.Namespace, diff --git a/internal/helper/kubernetes/suite_test.go b/internal/helper/kubernetes/suite_test.go new file mode 100644 index 00000000..648c0c9b --- /dev/null +++ b/internal/helper/kubernetes/suite_test.go @@ -0,0 +1,14 @@ +package kubernetes + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + // +kubebuilder:scaffold:imports +) + +func TestVersion(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Suite") +} diff --git a/internal/helper/kubernetes/version.go b/internal/helper/kubernetes/version.go index ac0957de..8e81083e 100644 --- a/internal/helper/kubernetes/version.go +++ b/internal/helper/kubernetes/version.go @@ -29,3 +29,41 @@ func GetVersion(client *discovery.DiscoveryClient) (*Version, error) { return &Version{Major: major, Minor: minor}, nil } + +func (v *Version) IsGreater(version *Version) bool { + if v.Major > version.Major { + return true + } + + if v.Major < version.Major { + return false + } + + if v.Minor > version.Minor { + return true + } + + if v.Minor < version.Minor { + return false + } + + // versions are equal + return false +} + +func (v *Version) IsEqual(version *Version) bool { + return (v.Major == version.Major && + v.Minor == version.Minor) +} + +func (v *Version) IsLower(version *Version) bool { + if v.IsGreater(version) { + return false + } + + if v.IsEqual(version) { + return false + } + + return true +} diff --git a/internal/helper/kubernetes/version_test.go b/internal/helper/kubernetes/version_test.go new file mode 100644 index 00000000..8d4c61cf --- /dev/null +++ b/internal/helper/kubernetes/version_test.go @@ -0,0 +1,81 @@ +package kubernetes + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + // +kubebuilder:scaffold:imports +) + +var _ = Describe("version test suite", func() { + When("testing IsEqual function", func() { + It("should be equal", func() { + v1 := Version{Major: 10, Minor: 10} + v2 := Version{Major: 10, Minor: 10} + Expect(v1.IsEqual(&v2)).To(BeTrue()) + }) + + It("should not be equal", func() { + v1 := Version{Major: 10, Minor: 10} + v2 := Version{Major: 11, Minor: 11} + Expect(v1.IsEqual(&v2)).To(BeFalse()) + }) + }) + + When("testing IsGreater function", func() { + It("should be greater", func() { + v1 := Version{Major: 11, Minor: 10} + v2 := Version{Major: 10, Minor: 10} + Expect(v1.IsGreater(&v2)).To(BeTrue()) + }) + + It("should be greater", func() { + v1 := Version{Major: 10, Minor: 11} + v2 := Version{Major: 10, Minor: 10} + Expect(v1.IsGreater(&v2)).To(BeTrue()) + }) + + It("should not be greater", func() { + v1 := Version{Major: 10, Minor: 10} + v2 := Version{Major: 10, Minor: 10} + Expect(v1.IsGreater(&v2)).To(BeFalse()) + }) + + It("should not be greater", func() { + v1 := Version{Major: 9, Minor: 10} + v2 := Version{Major: 10, Minor: 10} + Expect(v1.IsGreater(&v2)).To(BeFalse()) + }) + + It("should not be greater", func() { + v1 := Version{Major: 10, Minor: 9} + v2 := Version{Major: 10, Minor: 10} + Expect(v1.IsGreater(&v2)).To(BeFalse()) + }) + }) + + When("testing IsLower function", func() { + It("should be lower", func() { + v1 := Version{Major: 9, Minor: 10} + v2 := Version{Major: 10, Minor: 10} + Expect(v1.IsLower(&v2)).To(BeTrue()) + }) + + It("should be lower", func() { + v1 := Version{Major: 10, Minor: 9} + v2 := Version{Major: 10, Minor: 10} + Expect(v1.IsLower(&v2)).To(BeTrue()) + }) + + It("should not be lower", func() { + v1 := Version{Major: 10, Minor: 10} + v2 := Version{Major: 10, Minor: 10} + Expect(v1.IsLower(&v2)).To(BeFalse()) + }) + + It("should not be lower", func() { + v1 := Version{Major: 10, Minor: 10} + v2 := Version{Major: 9, Minor: 10} + Expect(v1.IsLower(&v2)).To(BeFalse()) + }) + }) +}) From 6064e4728ab06579756204f8cf31849bafb90d60 Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Wed, 1 Feb 2023 14:24:14 +0100 Subject: [PATCH 15/15] update deps Signed-off-by: Felix Breuer --- go.mod | 10 ++++----- go.sum | 70 ++++++++++++++++++++-------------------------------------- 2 files changed, 29 insertions(+), 51 deletions(-) diff --git a/go.mod b/go.mod index da94e473..c3cf0329 100644 --- a/go.mod +++ b/go.mod @@ -4,10 +4,10 @@ go 1.19 require ( github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc - github.com/envoyproxy/go-control-plane v0.10.3 + github.com/envoyproxy/go-control-plane v0.11.0 github.com/go-logr/logr v1.2.3 github.com/golang/protobuf v1.5.2 - github.com/gophercloud/gophercloud v1.1.1 + github.com/gophercloud/gophercloud v1.2.0 github.com/gophercloud/utils v0.0.0-20220927104426-4113af8d2663 github.com/onsi/ginkgo/v2 v2.8.0 github.com/onsi/gomega v1.26.0 @@ -46,11 +46,11 @@ require ( github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect + github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.8.0 // indirect - github.com/envoyproxy/protoc-gen-validate v0.6.7 // indirect + github.com/envoyproxy/protoc-gen-validate v0.9.1 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/fatih/color v1.12.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect @@ -85,7 +85,7 @@ require ( github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect - github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/afero v1.9.2 // indirect github.com/spf13/cobra v1.4.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect diff --git a/go.sum b/go.sum index a24c193e..d1a2a86f 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -15,6 +16,7 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= @@ -39,6 +41,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= @@ -61,7 +64,6 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= @@ -71,7 +73,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= @@ -81,9 +82,8 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -94,11 +94,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc h1:PYXxkRUBGUMa5xgMVMDl62vEklZvKpVaxQeN9ie7Hfk= github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -117,13 +112,11 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.3 h1:xdCVXxEe0Y3FQith+0cj2irwZudqGYvecuLB1HtdexY= -github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/go-control-plane v0.11.0 h1:jtLewhRR2vMRNnq2ZZUoCjUlgut+Y0+sDDWPOfwOi1o= +github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.7 h1:qcZcULcd/abmQg6dwigimCNEyi4gg31M/xaciQlDml8= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1 h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -177,7 +170,6 @@ github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -226,7 +218,6 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -244,6 +235,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -252,21 +244,19 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gophercloud/gophercloud v0.20.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4= -github.com/gophercloud/gophercloud v1.1.1 h1:MuGyqbSxiuVBqkPZ3+Nhbytk1xZxhmfCB2Rg1cJWFWM= -github.com/gophercloud/gophercloud v1.1.1/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= +github.com/gophercloud/gophercloud v1.2.0 h1:1oXyj4g54KBg/kFtCdMM6jtxSzeIyg8wv4z1HoGPp1E= +github.com/gophercloud/gophercloud v1.2.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gophercloud/utils v0.0.0-20220927104426-4113af8d2663 h1:cHUPA6mgL0RGwopSxYRil6v8mK4ab6yefs1PJRXPXUE= github.com/gophercloud/utils v0.0.0-20220927104426-4113af8d2663/go.mod h1:qOGlfG6OIJ193/c3Xt/XjOfHataNZdQcVgiu93LxBUM= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/hashicorp/go-uuid v1.0.2/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.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -301,7 +291,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= @@ -351,7 +340,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= @@ -382,7 +371,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil/v3 v3.22.12 h1:oG0ns6poeUSxf78JtOsfygNWuEHYYz8hnnNg7P04TJs= @@ -390,11 +378,9 @@ github.com/shirou/gopsutil/v3 v3.22.12/go.mod h1:Xd7P1kwZcp5VW52+9XsirIKd/BROzbb github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -432,8 +418,6 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= @@ -448,12 +432,13 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -482,7 +467,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -494,7 +478,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -532,12 +515,12 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -619,15 +602,16 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -707,6 +691,7 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= @@ -769,7 +754,6 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -782,13 +766,13 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 h1:a2S6M0+660BgMNl++4JPlcAO/CjkqYItDEZwkoDQK7c= google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -804,15 +788,11 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.52.3 h1:pf7sOysg4LdgBqduXveGKrcEwbStiK2rtfghdzlUYDQ= google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -828,7 +808,6 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -847,7 +826,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/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.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=