From cb534a83273126b0a9327257f9b8d6051b381bf6 Mon Sep 17 00:00:00 2001 From: Blake Pettersson Date: Thu, 17 Aug 2023 19:14:15 +0200 Subject: [PATCH 1/5] fix: apply ssa namespace twice In argoproj/argo-cd#13965, upgrading to client-go 0.26 uncovered an issue with existing namespaces not preserving labels and annotations when converting an existing namespace to use `managedNamespaceMetadata`. From 0.26 up, in order to preserve the existing behaviour what we need to do is to first apply the existing namespace with SSA and its preexisting labels and annotations. This also needs to be applied with another manager than the default one. After that initial apply, we proceed as normal with a ServerSideApply. This is a one-time thing for any existing namespace; we check if we need to perform this action by detecting if there is a preexisting SSA annotation on the namespace. Signed-off-by: Blake Pettersson --- pkg/sync/sync_context.go | 16 +++++++++++- pkg/sync/sync_context_test.go | 25 ++++++++++-------- .../kube/kubetest/mock_resource_operations.go | 26 ++++++++++++++++--- pkg/utils/kube/scheme/scheme.go | 2 ++ specs/design-top-down.md | 2 +- 5 files changed, 55 insertions(+), 16 deletions(-) diff --git a/pkg/sync/sync_context.go b/pkg/sync/sync_context.go index 50e23bc46..0aae36e6c 100644 --- a/pkg/sync/sync_context.go +++ b/pkg/sync/sync_context.go @@ -397,7 +397,7 @@ func (sc *syncContext) Sync() { } else { // Perform a `kubectl apply --dry-run` against all the manifests. This will detect most (but // not all) validation issues with the user's manifests (e.g. will detect syntax issues, but - // will not not detect if they are mutating immutable fields). If anything fails, we will refuse + // will not detect if they are mutating immutable fields). If anything fails, we will refuse // to perform the sync. we only wish to do this once per operation, performing additional dry-runs // is harmless, but redundant. The indicator we use to detect if we have already performed // the dry-run for this operation, is if the resource or hook list is empty. @@ -934,6 +934,20 @@ func (sc *syncContext) applyObject(t *syncTask, dryRun, force, validate bool) (c message, err = sc.resourceOps.CreateResource(context.TODO(), t.targetObj, dryRunStrategy, validate) } } else { + targetObjIsSSA := resourceutil.HasAnnotationOption(t.targetObj, common.AnnotationSyncOptions, common.SyncOptionServerSideApply) + liveObjIsNotSSA := t.liveObj != nil && !resourceutil.HasAnnotationOption(t.liveObj, common.AnnotationSyncOptions, common.SyncOptionServerSideApply) + if t.targetObj.GetKind() == kube.NamespaceKind && t.liveObj != nil && t.liveObj.GetKind() == kube.NamespaceKind && targetObjIsSSA && liveObjIsNotSSA { + // If there is a pre-existing live namespace, and if we also want to use managedNamespaceMetadata on an existing namespace, + // we need to do `kubectl apply` with the namespace as-is, using a different manager than the default one. + // The reason we do this is so that we can preserve existing labels and annotations on the namespace. + nsSpec := &v1.Namespace{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: kube.NamespaceKind}, ObjectMeta: metav1.ObjectMeta{Name: t.liveObj.GetName(), Annotations: t.liveObj.GetAnnotations(), Labels: t.liveObj.GetLabels(), Namespace: t.liveObj.GetNamespace()}} + liveCopy, err := kube.ToUnstructured(nsSpec) + + message, err = sc.resourceOps.ApplyResource(context.TODO(), liveCopy, dryRunStrategy, force, validate, serverSideApply, "argocd-controller-tmp") + if err != nil { + return common.ResultCodeSyncFailed, err.Error() + } + } message, err = sc.resourceOps.ApplyResource(context.TODO(), t.targetObj, dryRunStrategy, force, validate, serverSideApply, sc.serverSideApplyManager) } if err != nil { diff --git a/pkg/sync/sync_context_test.go b/pkg/sync/sync_context_test.go index 0c2e1e14c..1413df8dc 100644 --- a/pkg/sync/sync_context_test.go +++ b/pkg/sync/sync_context_test.go @@ -798,18 +798,20 @@ func withReplaceAndServerSideApplyAnnotations(un *unstructured.Unstructured) *un func TestSync_ServerSideApply(t *testing.T) { testCases := []struct { - name string - target *unstructured.Unstructured - live *unstructured.Unstructured - commandUsed string - serverSideApply bool - manager string + name string + target *unstructured.Unstructured + live *unstructured.Unstructured + commandUsed string + serverSideApply bool + manager string + expectedManagers []string }{ - {"NoAnnotation", NewPod(), NewPod(), "apply", false, "managerA"}, - {"ServerSideApplyAnnotationIsSet", withServerSideApplyAnnotation(NewPod()), NewPod(), "apply", true, "managerB"}, - {"ServerSideApplyAndReplaceAnnotationsAreSet", withReplaceAndServerSideApplyAnnotations(NewPod()), NewPod(), "replace", false, ""}, - {"ServerSideApplyAndReplaceAnnotationsAreSetNamespace", withReplaceAndServerSideApplyAnnotations(NewNamespace()), NewNamespace(), "update", false, ""}, - {"LiveObjectMissing", withReplaceAnnotation(NewPod()), nil, "create", false, ""}, + {"NoAnnotation", NewPod(), NewPod(), "apply", false, "managerA", []string{"managerA", "managerA"}}, + {"ServerSideApplyAnnotationIsSet", withServerSideApplyAnnotation(NewPod()), NewPod(), "apply", true, "managerB", []string{"managerB", "managerB"}}, + {"ServerSideApplyAndReplaceAnnotationsAreSet", withReplaceAndServerSideApplyAnnotations(NewPod()), NewPod(), "replace", false, "", nil}, + {"ServerSideApplyAndReplaceAnnotationsAreSetNamespace", withReplaceAndServerSideApplyAnnotations(NewNamespace()), NewNamespace(), "update", false, "", nil}, + {"LiveObjectMissing", withReplaceAnnotation(NewPod()), nil, "create", false, "", nil}, + {"ServerSideApplyWithExistingLiveNonSSAdNamespace", withServerSideApplyAnnotation(NewNamespace()), NewNamespace(), "apply", true, "managerA", []string{"argocd-controller-tmp", "managerA", "argocd-controller-tmp", "managerA"}}, } for _, tc := range testCases { @@ -834,6 +836,7 @@ func TestSync_ServerSideApply(t *testing.T) { resourceOps, _ := syncCtx.resourceOps.(*kubetest.MockResourceOps) assert.Equal(t, tc.commandUsed, resourceOps.GetLastResourceCommand(kube.GetResourceKey(tc.target))) assert.Equal(t, tc.serverSideApply, resourceOps.GetLastServerSideApply()) + assert.Equal(t, tc.expectedManagers, resourceOps.ServerSideApplyManagerCommands[kube.GetResourceKey(tc.target)]) assert.Equal(t, tc.manager, resourceOps.GetLastServerSideApplyManager()) }) } diff --git a/pkg/utils/kube/kubetest/mock_resource_operations.go b/pkg/utils/kube/kubetest/mock_resource_operations.go index 31ea6a0e4..2f5c069c5 100644 --- a/pkg/utils/kube/kubetest/mock_resource_operations.go +++ b/pkg/utils/kube/kubetest/mock_resource_operations.go @@ -14,9 +14,10 @@ import ( ) type MockResourceOps struct { - Commands map[string]KubectlOutput - Events chan watch.Event - DynamicClient dynamic.Interface + Commands map[string]KubectlOutput + ServerSideApplyManagerCommands map[kube.ResourceKey][]string + Events chan watch.Event + DynamicClient dynamic.Interface lastCommandPerResource map[kube.ResourceKey]string lastValidate bool @@ -73,6 +74,24 @@ func (r *MockResourceOps) SetLastServerSideApplyManager(manager string) { r.recordLock.Unlock() } +func (r *MockResourceOps) AddServerSideApplyManagerCommand(key kube.ResourceKey, manager string) { + r.recordLock.Lock() + if r.ServerSideApplyManagerCommands == nil { + + r.ServerSideApplyManagerCommands = map[kube.ResourceKey][]string{} + } + + strings := r.ServerSideApplyManagerCommands[key] + + if strings == nil { + r.ServerSideApplyManagerCommands[key] = []string{manager} + } else { + r.ServerSideApplyManagerCommands[key] = append(r.ServerSideApplyManagerCommands[key], manager) + } + + r.recordLock.Unlock() +} + func (r *MockResourceOps) SetLastResourceCommand(key kube.ResourceKey, cmd string) { r.recordLock.Lock() if r.lastCommandPerResource == nil { @@ -96,6 +115,7 @@ func (r *MockResourceOps) ApplyResource(ctx context.Context, obj *unstructured.U r.SetLastServerSideApply(serverSideApply) r.SetLastServerSideApplyManager(manager) r.SetLastResourceCommand(kube.GetResourceKey(obj), "apply") + r.AddServerSideApplyManagerCommand(kube.GetResourceKey(obj), manager) command, ok := r.Commands[obj.GetName()] if !ok { return "", nil diff --git a/pkg/utils/kube/scheme/scheme.go b/pkg/utils/kube/scheme/scheme.go index db105c814..f05979d5c 100644 --- a/pkg/utils/kube/scheme/scheme.go +++ b/pkg/utils/kube/scheme/scheme.go @@ -1,6 +1,8 @@ package scheme import ( + // TODO: change to this below? + // "k8s.io/client-go/kubernetes/scheme" "k8s.io/kubernetes/pkg/api/legacyscheme" _ "k8s.io/kubernetes/pkg/apis/admission/install" diff --git a/specs/design-top-down.md b/specs/design-top-down.md index 335fde1cb..e31f99dcc 100644 --- a/specs/design-top-down.md +++ b/specs/design-top-down.md @@ -115,7 +115,7 @@ The manifests generation is out of scope and should be implemented by the Engine ### Engine API -> `Sync` is a place holder to a real name. The name is still under discussion +> `Sync` is a placeholder to a real name. The name is still under discussion The engine API includes three main parts: - `Engine` golang interface From 826d56f18fb1063c747a676075b6cf5aa0220729 Mon Sep 17 00:00:00 2001 From: Blake Pettersson Date: Thu, 17 Aug 2023 23:59:25 +0200 Subject: [PATCH 2/5] chore: golangci-lint fixes Signed-off-by: Blake Pettersson --- go.mod | 4 +++- go.sum | 3 +++ pkg/sync/sync_context.go | 5 ++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 9e4b02627..1f4f18b3d 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/gnostic v0.5.7-v3refs github.com/spf13/cobra v1.6.0 github.com/stretchr/testify v1.8.1 - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 + golang.org/x/sync v0.1.0 google.golang.org/protobuf v1.28.1 k8s.io/api v0.26.4 k8s.io/apiextensions-apiserver v0.26.4 @@ -78,12 +78,14 @@ require ( github.com/stretchr/objx v0.5.0 // indirect github.com/xlab/treeprint v1.1.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect + golang.org/x/mod v0.7.0 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect + golang.org/x/tools v0.4.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index eff7f90e9..63d64fa66 100644 --- a/go.sum +++ b/go.sum @@ -356,6 +356,7 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB 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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -412,6 +413,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -519,6 +521,7 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/sync/sync_context.go b/pkg/sync/sync_context.go index 0aae36e6c..b5703e8e8 100644 --- a/pkg/sync/sync_context.go +++ b/pkg/sync/sync_context.go @@ -942,8 +942,11 @@ func (sc *syncContext) applyObject(t *syncTask, dryRun, force, validate bool) (c // The reason we do this is so that we can preserve existing labels and annotations on the namespace. nsSpec := &v1.Namespace{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: kube.NamespaceKind}, ObjectMeta: metav1.ObjectMeta{Name: t.liveObj.GetName(), Annotations: t.liveObj.GetAnnotations(), Labels: t.liveObj.GetLabels(), Namespace: t.liveObj.GetNamespace()}} liveCopy, err := kube.ToUnstructured(nsSpec) + if err != nil { + return common.ResultCodeSyncFailed, err.Error() + } - message, err = sc.resourceOps.ApplyResource(context.TODO(), liveCopy, dryRunStrategy, force, validate, serverSideApply, "argocd-controller-tmp") + _, err = sc.resourceOps.ApplyResource(context.TODO(), liveCopy, dryRunStrategy, force, validate, serverSideApply, "argocd-controller-tmp") if err != nil { return common.ResultCodeSyncFailed, err.Error() } From 69558bb3f1af42cd6ce48148a6b0906cf467b11b Mon Sep 17 00:00:00 2001 From: Blake Pettersson Date: Tue, 19 Sep 2023 16:01:57 +0200 Subject: [PATCH 3/5] Update pkg/sync/sync_context.go Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> Signed-off-by: Blake Pettersson --- pkg/sync/sync_context.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sync/sync_context.go b/pkg/sync/sync_context.go index b5703e8e8..0fbb4ca11 100644 --- a/pkg/sync/sync_context.go +++ b/pkg/sync/sync_context.go @@ -943,7 +943,7 @@ func (sc *syncContext) applyObject(t *syncTask, dryRun, force, validate bool) (c nsSpec := &v1.Namespace{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: kube.NamespaceKind}, ObjectMeta: metav1.ObjectMeta{Name: t.liveObj.GetName(), Annotations: t.liveObj.GetAnnotations(), Labels: t.liveObj.GetLabels(), Namespace: t.liveObj.GetNamespace()}} liveCopy, err := kube.ToUnstructured(nsSpec) if err != nil { - return common.ResultCodeSyncFailed, err.Error() + return common.ResultCodeSyncFailed, "failed to convert namespace spec to unstructured: " + err.Error() } _, err = sc.resourceOps.ApplyResource(context.TODO(), liveCopy, dryRunStrategy, force, validate, serverSideApply, "argocd-controller-tmp") From 45d43945567e7354a930a7f9dc1ac9911d12bb24 Mon Sep 17 00:00:00 2001 From: Blake Pettersson Date: Tue, 19 Sep 2023 16:02:06 +0200 Subject: [PATCH 4/5] Update pkg/sync/sync_context.go Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> Signed-off-by: Blake Pettersson --- pkg/sync/sync_context.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sync/sync_context.go b/pkg/sync/sync_context.go index 0fbb4ca11..3823d9d16 100644 --- a/pkg/sync/sync_context.go +++ b/pkg/sync/sync_context.go @@ -948,7 +948,7 @@ func (sc *syncContext) applyObject(t *syncTask, dryRun, force, validate bool) (c _, err = sc.resourceOps.ApplyResource(context.TODO(), liveCopy, dryRunStrategy, force, validate, serverSideApply, "argocd-controller-tmp") if err != nil { - return common.ResultCodeSyncFailed, err.Error() + return common.ResultCodeSyncFailed, "failed to apply existing namespace with temp field manager: " + err.Error() } } message, err = sc.resourceOps.ApplyResource(context.TODO(), t.targetObj, dryRunStrategy, force, validate, serverSideApply, sc.serverSideApplyManager) From 0115c94b842ab70c499b969436ee86541a27bd58 Mon Sep 17 00:00:00 2001 From: Blake Pettersson Date: Sat, 14 Oct 2023 00:16:25 +0200 Subject: [PATCH 5/5] chore: go mod tidy Signed-off-by: Blake Pettersson --- go.mod | 2 -- go.sum | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 1f4f18b3d..4f7979ff0 100644 --- a/go.mod +++ b/go.mod @@ -78,14 +78,12 @@ require ( github.com/stretchr/objx v0.5.0 // indirect github.com/xlab/treeprint v1.1.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect - golang.org/x/mod v0.7.0 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect - golang.org/x/tools v0.4.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 63d64fa66..eaa849b27 100644 --- a/go.sum +++ b/go.sum @@ -356,7 +356,6 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB 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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -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= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -411,8 +410,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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= @@ -521,7 +519,6 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=