From e6e78ca379f371dee199e4a81e4e6e229c3ce95d Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Wed, 15 Mar 2023 11:36:13 +0100 Subject: [PATCH 01/21] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20to=20go=20?= =?UTF-8?q?`1.20`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Elis Lulja --- go.mod | 141 +++---- go.sum | 1168 +++++--------------------------------------------------- 2 files changed, 159 insertions(+), 1150 deletions(-) diff --git a/go.mod b/go.mod index 45a22b1..ea8c965 100644 --- a/go.mod +++ b/go.mod @@ -1,98 +1,101 @@ module github.com/CloudNativeSDWAN/cnwan-operator -go 1.17 +go 1.20 require ( - cloud.google.com/go/compute v1.15.1 // indirect + cloud.google.com/go/compute/metadata v0.2.3 cloud.google.com/go/servicedirectory v1.8.0 - github.com/aws/aws-sdk-go v1.44.78 - github.com/aws/aws-sdk-go-v2 v1.17.4 - github.com/aws/aws-sdk-go-v2/config v1.18.13 - github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.19.2 + github.com/aws/aws-sdk-go v1.44.221 + github.com/aws/aws-sdk-go-v2 v1.17.6 + github.com/aws/aws-sdk-go-v2/config v1.18.17 + github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.20.1 + github.com/go-logr/logr v1.2.3 + github.com/googleapis/gax-go/v2 v2.7.1 + github.com/stretchr/testify v1.8.2 + go.etcd.io/etcd/api/v3 v3.5.7 + go.etcd.io/etcd/client/v3 v3.5.7 + go.uber.org/zap v1.24.0 + google.golang.org/api v0.112.0 + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 + google.golang.org/grpc v1.53.0 + gopkg.in/yaml.v3 v3.0.1 + k8s.io/api v0.26.2 + k8s.io/apimachinery v0.26.2 + k8s.io/client-go v0.26.2 + sigs.k8s.io/controller-runtime v0.14.5 +) + +require ( + cloud.google.com/go/compute v1.18.0 // indirect + cloud.google.com/go/iam v0.12.0 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.17 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.12.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 // indirect + github.com/aws/smithy-go v1.13.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/evanphx/json-patch v4.9.0+incompatible // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect - github.com/go-logr/logr v0.1.0 - github.com/go-logr/zapr v0.1.0 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/evanphx/json-patch v4.12.0+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-logr/zapr v1.2.3 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/swag v0.19.14 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/gax-go/v2 v2.7.0 - github.com/googleapis/gnostic v0.3.1 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/imdario/mergo v0.3.9 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/imdario/mergo v0.3.6 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/json-iterator/go v1.1.11 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect - github.com/nxadm/tail v1.4.8 // indirect - github.com/onsi/ginkgo v1.16.5 - github.com/onsi/gomega v1.20.0 + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.11.1 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.26.0 // indirect - github.com/prometheus/procfs v0.6.0 // indirect + github.com/prometheus/client_golang v1.14.0 // indirect + 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/pflag v1.0.5 // indirect - github.com/stretchr/testify v1.8.2 - go.etcd.io/etcd/api/v3 v3.5.7 go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect - go.etcd.io/etcd/client/v3 v3.5.7 go.opencensus.io v0.24.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.24.0 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect - golang.org/x/net v0.5.0 // indirect - golang.org/x/oauth2 v0.4.0 // indirect - golang.org/x/sys v0.4.0 // indirect - golang.org/x/text v0.6.0 // indirect - golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect - gomodules.xyz/jsonpatch/v2 v2.0.1 // indirect - google.golang.org/api v0.105.0 + golang.org/x/net v0.8.0 // indirect + golang.org/x/oauth2 v0.6.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/term v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.3.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f - google.golang.org/grpc v1.53.0 google.golang.org/protobuf v1.28.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.18.6 - k8s.io/apiextensions-apiserver v0.18.6 // indirect - k8s.io/apimachinery v0.18.6 - k8s.io/client-go v0.18.6 - k8s.io/klog v1.0.0 // indirect - k8s.io/klog/v2 v2.0.0 // indirect - k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 // indirect - k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 // indirect - sigs.k8s.io/controller-runtime v0.6.3 - sigs.k8s.io/structured-merge-diff/v3 v3.0.0 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect -) - -require cloud.google.com/go/compute/metadata v0.2.3 - -require ( - cloud.google.com/go/iam v0.8.0 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.13 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.12.2 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.18.3 // indirect - github.com/aws/smithy-go v1.13.5 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect + k8s.io/apiextensions-apiserver v0.26.1 // indirect + k8s.io/component-base v0.26.1 // indirect + k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect + k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 61eef0a..a3efed8 100644 --- a/go.sum +++ b/go.sum @@ -3,7 +3,6 @@ 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= @@ -14,600 +13,106 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 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= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= -cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= -cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= -cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= -cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= -cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= -cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= -cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= -cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= -cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= -cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= -cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= -cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= -cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= -cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= -cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= -cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= -cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= -cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= -cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= -cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= -cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= -cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= -cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= -cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= -cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= -cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= -cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= -cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= -cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= -cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= -cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= -cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= -cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= -cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= -cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= -cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= -cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= -cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= -cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= -cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= -cloud.google.com/go/compute/metadata v0.2.2/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= -cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= -cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= -cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= -cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= -cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= -cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= -cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= -cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= -cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= -cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= -cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= -cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= -cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= -cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= -cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= -cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= -cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= -cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= -cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= -cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= -cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= -cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= -cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= -cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= -cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= -cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= -cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= -cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= -cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= -cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= -cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= -cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= -cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= -cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= -cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= -cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= -cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= -cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= -cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= -cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= -cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk= -cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= -cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= -cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= -cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= -cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= -cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= -cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= -cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= -cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= -cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= -cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= -cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= -cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= -cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= -cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= -cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= -cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= -cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= -cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= -cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= -cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= -cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= -cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= -cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= -cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= -cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= -cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= -cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= -cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= -cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= -cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= -cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= -cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= -cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= -cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= -cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= -cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= -cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= -cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= -cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= -cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= -cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= -cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= -cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= -cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= -cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= -cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= -cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= -cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= -cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= -cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= -cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= -cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= -cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= -cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= -cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= -cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= -cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= -cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= -cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= -cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= -cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= -cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= -cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= -cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= -cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= -cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= -cloud.google.com/go/servicedirectory v1.8.0 h1:DPvPdb6O/lg7xK+BFKlzZN+w6upeJ/bbfcUnnqU66b8= cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= -cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= -cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= -cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= -cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= -cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= -cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= -cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= -cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= -cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 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= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= -cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= -cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= -cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= -cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= -cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= -cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= -cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= -cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= -cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= -cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= -cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= -cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= -cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= -cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= -cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= -cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= -cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= -cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= -cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= -cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= -cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= -cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= -cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= -cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= -cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= -cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= -cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= 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.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 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/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.44.78 h1:B/V28YXFLmxjMQqJeyCt7NDRIJdep0sJixIAeee2BF0= -github.com/aws/aws-sdk-go v1.44.78/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go-v2 v1.17.4 h1:wyC6p9Yfq6V2y98wfDsj6OnNQa4w2BLGCLIxzNhwOGY= -github.com/aws/aws-sdk-go-v2 v1.17.4/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2/config v1.18.13 h1:v0xlYqbO6/EVlM8tUn2QEOA7btQxcgidEq2JRDBPTho= -github.com/aws/aws-sdk-go-v2/config v1.18.13/go.mod h1:r39wGSZB7wPDW1i54JyQXUpc5KsWjh5z/3S5D9eCqDg= -github.com/aws/aws-sdk-go-v2/credentials v1.13.13 h1:zw1KAc1kl00NYd3ofVmFrb09qnYlSQMeh+fmlQRAihI= -github.com/aws/aws-sdk-go-v2/credentials v1.13.13/go.mod h1:DW9nbIIF9MrIja0cBQrUpeWYQMSlNmP8fevLUyF9W38= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22 h1:3aMfcTmoXtTZnaT86QlVaYh+BRMbvrrmZwIQ5jWqCZQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22/go.mod h1:YGSIJyQ6D6FjKMQh16hVFSIUD54L4F7zTGePqYMYYJU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28 h1:r+XwaCLpIvCKjBIYy/HVZujQS9tsz5ohHG3ZIe0wKoE= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28/go.mod h1:3lwChorpIM/BhImY/hy+Z6jekmN92cXGPI1QJasVPYY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22 h1:7AwGYXDdqRQYsluvKFmWoqpcOQJ4bH634SkYf3FNj/A= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22/go.mod h1:EqK7gVrIGAHyZItrD1D8B0ilgwMD1GiWAmbU4u/JHNk= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 h1:J4xhFd6zHhdF9jPP0FQJ6WknzBboGMBNjKOv4iTuw4A= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29/go.mod h1:TwuqRBGzxjQJIwH16/fOZodwXt2Zxa9/cwJC5ke4j7s= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22 h1:LjFQf8hFuMO22HkV5VWGLBvmCLBCLPivUAmpdpnp4Vs= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22/go.mod h1:xt0Au8yPIwYXf/GYPy/vl4K3CgwhfQMYbrH7DlUUIws= -github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.19.2 h1:3MTUlQrl3wZkyK59bcVBfnv0sOZ3V5/LAxa5SufCkMA= -github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.19.2/go.mod h1:Dp6t5jdFeWpbNgDUX7HmnA/ZbnDkHwDseVl0IvESFSE= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.2 h1:EN102fWY7hI5u/2FPheTrwwMHkSXfl49RYkeEnJsrCU= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.2/go.mod h1:IgV8l3sj22nQDd5qcAGY0WenwCzCphqdbFOpfktZPrI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.2 h1:f1lmlce7r13CX1BPyPqt9oh/H+uqOWc9367lDoGGwNQ= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.2/go.mod h1:O1YSOg3aekZibh2SngvCRRG+cRHKKlYgxf/JBF/Kr/k= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.3 h1:s49mSnsBZEXjfGBkRfmK+nPqzT7Lt3+t2SmAKNyHblw= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.3/go.mod h1:b+psTJn33Q4qGoDaM7ZiOVVG8uVjGI6HaZ8WBHdgDgU= -github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= +github.com/aws/aws-sdk-go v1.44.221/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go-v2 v1.17.6/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2/config v1.18.17/go.mod h1:Lj3E7XcxJnxMa+AYo89YiL68s1cFJRGduChynYU67VA= +github.com/aws/aws-sdk-go-v2/credentials v1.13.17/go.mod h1:K9xeFo1g/YPMguMUD69YpwB4Nyi6W/5wn706xIInJFg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.0/go.mod h1:neYVaeKr5eT7BzwULuG2YbLhzWZ22lpjKdCybR7AXrQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30/go.mod h1:LUBAO3zNXQjoONBKn/kR1y0Q4cj/D02Ts0uHYjcCQLM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24/go.mod h1:gAuCezX/gob6BSMbItsSlMb6WZGV7K2+fWOvk8xBSto= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31/go.mod h1:5zUjguZfG5qjhG9/wqmuyHRyUftl2B5Cp6NNxNC6kRA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24/go.mod h1:HMA4FZG6fyib+NDo5bpIxX1EhYjrAOveZJY2YR0xrNE= +github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.20.1/go.mod h1:kXRUSok2dElGBpwEsTiKl4BVKao/WUfVGj6XSX/I5ko= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.5/go.mod h1:vuWiaDB30M/QTC+lI3Wj6S/zb7tpUK2MSYgy3Guh2L0= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5/go.mod h1:QjxpHmCwAg0ESGtPQnLIVp7SedTOBMYy+Slr3IfMKeI= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.6/go.mod h1:48WJ9l3dwP0GSHWGc5sFGGlCkuA82Mc2xnw+T6Q8aDw= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 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/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/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-20211001041855-01bcc9b48dfe/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/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/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.20210217033140-668b12f5399d/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.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= -github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54= -github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= -github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= -github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= -github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= -github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= -github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= -github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 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 h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -615,9 +120,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -633,12 +135,10 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -646,22 +146,15 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.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.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -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= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -669,204 +162,88 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 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/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -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/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= 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/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= -github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -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/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= 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/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -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= -github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= -github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= -github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= -github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 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/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -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/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -878,76 +255,33 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY= go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA= -go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg= go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY= -go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4= go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw= -go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 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.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -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.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -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.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/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-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/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-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -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 h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -970,8 +304,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 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= @@ -980,24 +312,13 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 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.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.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1006,9 +327,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1019,66 +337,27 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -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-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/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= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1089,36 +368,20 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/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-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1137,89 +400,38 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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-20210403161142-5e06dd20ab57/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-20210514084401-e8d321eab015/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-20210603125802-9665404d3644/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-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/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-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/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-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1228,14 +440,12 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1262,33 +472,13 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/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.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0= -gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= +gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1305,50 +495,13 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= -google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= -google.golang.org/api v0.105.0 h1:t6P9Jj+6XTn4U9I2wycQai6Q/Kz7iOT+QzjJ3G2V4x8= -google.golang.org/api v0.105.0/go.mod h1:qh7eD5FJks5+BcE+cjBIm6Gz8vioK7EHvnlniqXBnqI= +google.golang.org/api v0.112.0/go.mod h1:737UfWHNsOq4F3REUTmb+GN9pugkgNLCayLTfoIKpPc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1373,102 +526,18 @@ 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= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -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-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= -google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= -google.golang.org/genproto v0.0.0-20221206210731-b1a01be3a5f6/go.mod h1:1dOng4TWOomJrDGhpXjfCD35wQC6jnC7HpRmOFRqEV0= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -1477,35 +546,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 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.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.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.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1518,40 +560,25 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 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= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1559,39 +586,18 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.18.6 h1:osqrAXbOQjkKIWDTjrqxWQ3w0GkKb1KA1XkUGHHYpeE= -k8s.io/api v0.18.6/go.mod h1:eeyxr+cwCjMdLAmr2W3RyDI0VvTawSg/3RFFBEnmZGI= -k8s.io/apiextensions-apiserver v0.18.6 h1:vDlk7cyFsDyfwn2rNAO2DbmUbvXy5yT5GE3rrqOzaMo= -k8s.io/apiextensions-apiserver v0.18.6/go.mod h1:lv89S7fUysXjLZO7ke783xOwVTm6lKizADfvUM/SS/M= -k8s.io/apimachinery v0.18.6 h1:RtFHnfGNfd1N0LeSrKCUznz5xtUP1elRGvHJbL3Ntag= -k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= -k8s.io/apiserver v0.18.6/go.mod h1:Zt2XvTHuaZjBz6EFYzpp+X4hTmgWGy8AthNVnTdm3Wg= -k8s.io/client-go v0.18.6 h1:I+oWqJbibLSGsZj8Xs8F0aWVXJVIoUHWaaJV3kUN/Zw= -k8s.io/client-go v0.18.6/go.mod h1:/fwtGLjYMS1MaM5oi+eXhKwG+1UHidUEXRh6cNsdO0Q= -k8s.io/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= -k8s.io/component-base v0.18.6/go.mod h1:knSVsibPR5K6EW2XOjEHik6sdU5nCvKMrzMt2D4In14= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog/v2 v2.0.0 h1:Foj74zO6RbjjP4hBEKjnYtjjAhGg4jNynUdYF6fJrok= -k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY= -k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 h1:v8ud2Up6QK1lNOKFgiIVrZdMg7MpmSnvtrOieolJKoE= -k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU= +k8s.io/apiextensions-apiserver v0.26.1/go.mod h1:AptjOSXDGuE0JICx/Em15PaoO7buLwTs0dGleIHixSM= +k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= +k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= +k8s.io/component-base v0.26.1/go.mod h1:VHrLR0b58oC035w6YQiBSbtsf0ThuSwXP+p5dD/kAWU= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= -sigs.k8s.io/controller-runtime v0.6.3 h1:SBbr+inLPEKhvlJtrvDcwIpm+uhDvp63Bl72xYJtoOE= -sigs.k8s.io/controller-runtime v0.6.3/go.mod h1:WlZNXcM0++oyaQt4B7C2lEE5JYRs8vJUzRP4N4JpdAY= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/controller-runtime v0.14.5/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= From 33dc681509afd96646afd8b9405646bc1cacdd11 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Wed, 15 Mar 2023 11:36:59 +0100 Subject: [PATCH 02/21] feat(ctrl): Create manager constructor Signed-off-by: Elis Lulja --- controllers/manager.go | 54 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 controllers/manager.go diff --git a/controllers/manager.go b/controllers/manager.go new file mode 100644 index 0000000..fbb6613 --- /dev/null +++ b/controllers/manager.go @@ -0,0 +1,54 @@ +// Copyright (c) 2023 Cisco Systems, Inc. and its affiliates +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package controllers + +import ( + "fmt" + + k8sruntime "k8s.io/apimachinery/pkg/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + _ "k8s.io/client-go/plugin/pkg/client/auth" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/controller-runtime/pkg/client/config" + "sigs.k8s.io/controller-runtime/pkg/manager" +) + +func NewManager(kubeconfigPath string) (manager.Manager, error) { + scheme := k8sruntime.NewScheme() + if err := clientgoscheme.AddToScheme(scheme); err != nil { + return nil, fmt.Errorf("could not add to scheme: %w", err) + } + + cfg, err := func() (*rest.Config, error) { + if kubeconfigPath == "" { + return config.GetConfig() + } + + return clientcmd.BuildConfigFromFlags("", kubeconfigPath) + }() + if err != nil { + return nil, fmt.Errorf("could not get config: %w", err) + } + + return manager.New(cfg, manager.Options{ + Scheme: scheme, + LeaderElection: false, + MetricsBindAddress: "0", + }) +} From 7adbd6b5be77dc218ae83163576b07681d82efdd Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Wed, 15 Mar 2023 11:44:54 +0100 Subject: [PATCH 03/21] refactor(ctrls): create new namespace controller Signed-off-by: Elis Lulja --- controllers/namespace.go | 104 +++++++++++++++++++++++++++++++++++++++ go.mod | 5 +- go.sum | 8 ++- 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 controllers/namespace.go diff --git a/controllers/namespace.go b/controllers/namespace.go new file mode 100644 index 0000000..ed57b87 --- /dev/null +++ b/controllers/namespace.go @@ -0,0 +1,104 @@ +// Copyright (c) 2023 Cisco Systems, Inc. and its affiliates +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package controllers + +import ( + "context" + + "github.com/rs/zerolog" + corev1 "k8s.io/api/core/v1" + _ "k8s.io/client-go/plugin/pkg/client/auth" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +const ( + nsCtrlName string = "namespace-event-handler" +) + +type namespaceEventHandler struct { + log zerolog.Logger +} + +func NewNamespaceController(mgr manager.Manager, log zerolog.Logger) (controller.Controller, error) { + nsHandler := &namespaceEventHandler{log} + + c, err := controller.New(nsCtrlName, mgr, controller.Options{ + Reconciler: reconcile.Func(func(c context.Context, r reconcile.Request) (reconcile.Result, error) { + return reconcile.Result{}, nil + }), + }) + + if err != nil { + return nil, err + } + + err = c.Watch(&source.Kind{Type: &corev1.Namespace{}}, nsHandler) + if err != nil { + return nil, err + } + + return c, nil +} + +// Update handles update events. +func (n *namespaceEventHandler) Update(ue event.UpdateEvent, wq workqueue.RateLimitingInterface) { + l := n.log.With().Str("event-handler", "Update").Logger() + defer wq.Done(ue.ObjectNew) + + // TODO + _ = l +} + +// Delete handles delete events. +func (n *namespaceEventHandler) Delete(de event.DeleteEvent, wq workqueue.RateLimitingInterface) { + defer wq.Done(de.Object) + + namespace, ok := de.Object.(*corev1.Namespace) + if !ok { + return + } + + // TODO + _ = namespace +} + +// Create handles create events. +func (n *namespaceEventHandler) Create(ce event.CreateEvent, wq workqueue.RateLimitingInterface) { + l := n.log.With().Str("event-handler", "Create").Logger() + defer wq.Done(ce.Object) + + namespace, ok := ce.Object.(*corev1.Namespace) + if !ok { + return + } + + // TODO + _, _ = l, namespace +} + +// Generic handles generic events. +func (n *namespaceEventHandler) Generic(ge event.GenericEvent, wq workqueue.RateLimitingInterface) { + // We don't really know what to do with generic events. + // We will just ignore this. + wq.Done(ge.Object) +} diff --git a/go.mod b/go.mod index ea8c965..3d331fa 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.20.1 github.com/go-logr/logr v1.2.3 github.com/googleapis/gax-go/v2 v2.7.1 + github.com/rs/zerolog v1.29.0 github.com/stretchr/testify v1.8.2 go.etcd.io/etcd/api/v3 v3.5.7 go.etcd.io/etcd/client/v3 v3.5.7 @@ -41,7 +42,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/coreos/go-semver v0.3.0 // indirect - github.com/coreos/go-systemd/v22 v22.3.2 // indirect + github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect @@ -64,6 +65,8 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.6 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect diff --git a/go.sum b/go.sum index a3efed8..8f0d1d5 100644 --- a/go.sum +++ b/go.sum @@ -70,7 +70,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -199,6 +199,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -237,6 +239,8 @@ 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/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= 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= @@ -406,6 +410,8 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From 880c67c4e18f839365ee17c7fb37590098c62a5c Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Wed, 15 Mar 2023 12:25:13 +0100 Subject: [PATCH 04/21] refactor(ns-ctrl): parse namespace labels Signed-off-by: Elis Lulja --- controllers/errors.go | 25 ++++++++++++ controllers/namespace.go | 84 +++++++++++++++++++++++++++++++--------- 2 files changed, 90 insertions(+), 19 deletions(-) create mode 100644 controllers/errors.go diff --git a/controllers/errors.go b/controllers/errors.go new file mode 100644 index 0000000..f1d96ee --- /dev/null +++ b/controllers/errors.go @@ -0,0 +1,25 @@ +// Copyright (c) 2023 Cisco Systems, Inc. and its affiliates +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package controllers + +import "errors" + +var ( + ErrorInvalidManager = errors.New("invalid manager provided") + ErrorInvalidNamespaceOptions = errors.New("invalid namespace options provided") +) diff --git a/controllers/namespace.go b/controllers/namespace.go index ed57b87..6e8e666 100644 --- a/controllers/namespace.go +++ b/controllers/namespace.go @@ -32,16 +32,32 @@ import ( ) const ( - nsCtrlName string = "namespace-event-handler" + nsCtrlName string = "namespace-event-handler" + watchLabel string = "operator.cnwan.io/watch" + watchEnabledLabel string = "enabled" + watchDisabledLabel string = "disabled" ) type namespaceEventHandler struct { + // client log zerolog.Logger + NamespaceControllerOptions } -func NewNamespaceController(mgr manager.Manager, log zerolog.Logger) (controller.Controller, error) { - nsHandler := &namespaceEventHandler{log} +type NamespaceControllerOptions struct { + WatchAllByDefault bool + ServiceAnnotations []string +} +func NewNamespaceController(mgr manager.Manager, opts *NamespaceControllerOptions, log zerolog.Logger) (controller.Controller, error) { + if mgr == nil { + return nil, ErrorInvalidManager + } + if opts == nil { + return nil, ErrorInvalidNamespaceOptions + } + + nsHandler := &namespaceEventHandler{log: log} c, err := controller.New(nsCtrlName, mgr, controller.Options{ Reconciler: reconcile.Func(func(c context.Context, r reconcile.Request) (reconcile.Result, error) { return reconcile.Result{}, nil @@ -60,13 +76,43 @@ func NewNamespaceController(mgr manager.Manager, log zerolog.Logger) (controller return c, nil } +// Create handles create events. +func (n *namespaceEventHandler) Create(ce event.CreateEvent, wq workqueue.RateLimitingInterface) { + defer wq.Done(ce.Object) + + namespace, ok := ce.Object.(*corev1.Namespace) + if !ok { + return + } + + if !shouldWatchLabel(namespace.Labels, n.WatchAllByDefault) { + return + } + + // TODO: send event to listener that a new namespace has been created. +} + // Update handles update events. func (n *namespaceEventHandler) Update(ue event.UpdateEvent, wq workqueue.RateLimitingInterface) { - l := n.log.With().Str("event-handler", "Update").Logger() defer wq.Done(ue.ObjectNew) - // TODO - _ = l + curr, currok := ue.ObjectNew.(*corev1.Namespace) + old, oldok := ue.ObjectOld.(*corev1.Namespace) + if !currok || !oldok { + return + } + + watchedBefore := shouldWatchLabel(curr.Labels, n.WatchAllByDefault) + watchNow := shouldWatchLabel(old.Labels, n.WatchAllByDefault) + + switch { + case !watchedBefore && !watchNow: + return + case !watchedBefore && watchNow: + // TODO: send create ns, send create for all services inside it + case watchedBefore && !watchNow: + // TODO: send delete for all services inside it, send delete ns + } } // Delete handles delete events. @@ -78,22 +124,11 @@ func (n *namespaceEventHandler) Delete(de event.DeleteEvent, wq workqueue.RateLi return } - // TODO - _ = namespace -} - -// Create handles create events. -func (n *namespaceEventHandler) Create(ce event.CreateEvent, wq workqueue.RateLimitingInterface) { - l := n.log.With().Str("event-handler", "Create").Logger() - defer wq.Done(ce.Object) - - namespace, ok := ce.Object.(*corev1.Namespace) - if !ok { + if !shouldWatchLabel(namespace.Labels, n.WatchAllByDefault) { return } - // TODO - _, _ = l, namespace + // TODO: send event to listener that a namespace has been deleted. } // Generic handles generic events. @@ -102,3 +137,14 @@ func (n *namespaceEventHandler) Generic(ge event.GenericEvent, wq workqueue.Rate // We will just ignore this. wq.Done(ge.Object) } + +func shouldWatchLabel(labels map[string]string, watchAllByDefault bool) bool { + switch labels[watchLabel] { + case watchEnabledLabel: + return true + case watchDisabledLabel: + return false + default: + return watchAllByDefault + } +} From ed613a04c5762f1b618fea95161366c66439f7f3 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Thu, 16 Mar 2023 10:28:13 +0100 Subject: [PATCH 05/21] refactor(ctrls): create new utility functions Signed-off-by: Elis Lulja --- controllers/utils.go | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/controllers/utils.go b/controllers/utils.go index 013839c..cea4bd8 100644 --- a/controllers/utils.go +++ b/controllers/utils.go @@ -1,4 +1,4 @@ -// Copyright © 2021 Cisco +// Copyright © 2021 - 2023 Cisco // // SPDX-License-Identifier: Apache-2.0 // @@ -20,7 +20,10 @@ package controllers import ( "fmt" + "net" "strings" + + corev1 "k8s.io/api/core/v1" ) // filterAnnotations is used to remove annotations that should be ignored @@ -64,3 +67,37 @@ func filterAnnotations(currentAnnotations map[string]string, filter []string) ma return filtered } + +func shouldWatchLabel(labels map[string]string, watchAllByDefault bool) bool { + switch labels[watchLabel] { + case watchEnabledLabel: + return true + case watchDisabledLabel: + return false + default: + return watchAllByDefault + } +} + +func getIPsFromService(service *corev1.Service) ([]string, error) { + ips := []string{} + ips = append(ips, service.Spec.ExternalIPs...) + + // Get data from load balancers + for _, ing := range service.Status.LoadBalancer.Ingress { + if ing.IP != "" { + ips = append(ips, ing.IP) + } + + if ing.Hostname != "" { + if resolvedIPs, err := net.LookupHost(ing.Hostname); err != nil { + return nil, err + } else { + ips = append(ips, resolvedIPs...) + } + } + ips = append(ips, ing.IP) + } + + return ips, nil +} From 2f2439866da7ef9c094764cd45ca93b7d7bf9e98 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Thu, 16 Mar 2023 10:36:12 +0100 Subject: [PATCH 06/21] refactor(ns-ctrl): use common controller options Signed-off-by: Elis Lulja --- controllers/errors.go | 4 ++-- controllers/namespace.go | 35 ++++++++++++----------------------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/controllers/errors.go b/controllers/errors.go index f1d96ee..676809d 100644 --- a/controllers/errors.go +++ b/controllers/errors.go @@ -20,6 +20,6 @@ package controllers import "errors" var ( - ErrorInvalidManager = errors.New("invalid manager provided") - ErrorInvalidNamespaceOptions = errors.New("invalid namespace options provided") + ErrorInvalidManager = errors.New("invalid manager provided") + ErrorInvalidControllerOptions = errors.New("invalid controller options provided") ) diff --git a/controllers/namespace.go b/controllers/namespace.go index 6e8e666..db8e057 100644 --- a/controllers/namespace.go +++ b/controllers/namespace.go @@ -38,23 +38,23 @@ const ( watchDisabledLabel string = "disabled" ) +type ControllerOptions struct { + WatchNamespacesByDefault bool + ServiceAnnotations []string +} + type namespaceEventHandler struct { // client log zerolog.Logger - NamespaceControllerOptions -} - -type NamespaceControllerOptions struct { - WatchAllByDefault bool - ServiceAnnotations []string + ControllerOptions } -func NewNamespaceController(mgr manager.Manager, opts *NamespaceControllerOptions, log zerolog.Logger) (controller.Controller, error) { +func NewNamespaceController(mgr manager.Manager, opts *ControllerOptions, log zerolog.Logger) (controller.Controller, error) { if mgr == nil { return nil, ErrorInvalidManager } if opts == nil { - return nil, ErrorInvalidNamespaceOptions + return nil, ErrorInvalidControllerOptions } nsHandler := &namespaceEventHandler{log: log} @@ -85,7 +85,7 @@ func (n *namespaceEventHandler) Create(ce event.CreateEvent, wq workqueue.RateLi return } - if !shouldWatchLabel(namespace.Labels, n.WatchAllByDefault) { + if !shouldWatchLabel(namespace.Labels, n.WatchNamespacesByDefault) { return } @@ -102,8 +102,8 @@ func (n *namespaceEventHandler) Update(ue event.UpdateEvent, wq workqueue.RateLi return } - watchedBefore := shouldWatchLabel(curr.Labels, n.WatchAllByDefault) - watchNow := shouldWatchLabel(old.Labels, n.WatchAllByDefault) + watchedBefore := shouldWatchLabel(curr.Labels, n.WatchNamespacesByDefault) + watchNow := shouldWatchLabel(old.Labels, n.WatchNamespacesByDefault) switch { case !watchedBefore && !watchNow: @@ -124,7 +124,7 @@ func (n *namespaceEventHandler) Delete(de event.DeleteEvent, wq workqueue.RateLi return } - if !shouldWatchLabel(namespace.Labels, n.WatchAllByDefault) { + if !shouldWatchLabel(namespace.Labels, n.WatchNamespacesByDefault) { return } @@ -137,14 +137,3 @@ func (n *namespaceEventHandler) Generic(ge event.GenericEvent, wq workqueue.Rate // We will just ignore this. wq.Done(ge.Object) } - -func shouldWatchLabel(labels map[string]string, watchAllByDefault bool) bool { - switch labels[watchLabel] { - case watchEnabledLabel: - return true - case watchDisabledLabel: - return false - default: - return watchAllByDefault - } -} From 2c3210c2895e98980e5d95b9c6ee897b36092f8c Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Thu, 16 Mar 2023 10:36:44 +0100 Subject: [PATCH 07/21] refactor(ctrl): create new service controller Signed-off-by: Elis Lulja --- controllers/service.go | 228 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 controllers/service.go diff --git a/controllers/service.go b/controllers/service.go new file mode 100644 index 0000000..9d2d914 --- /dev/null +++ b/controllers/service.go @@ -0,0 +1,228 @@ +// Copyright (c) 2023 Cisco Systems, Inc. and its affiliates +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package controllers + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "fmt" + + "github.com/rs/zerolog" + corev1 "k8s.io/api/core/v1" + _ "k8s.io/client-go/plugin/pkg/client/auth" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +const ( + servCtrlName string = "service-event-handler" +) + +type serviceEventHandler struct { + // client + log zerolog.Logger + ControllerOptions +} + +func NewServiceController(mgr manager.Manager, opts *ControllerOptions, log zerolog.Logger) (controller.Controller, error) { + if mgr == nil { + return nil, ErrorInvalidManager + } + if opts == nil { + return nil, ErrorInvalidControllerOptions + } + + servHandler := &namespaceEventHandler{log: log} + c, err := controller.New(nsCtrlName, mgr, controller.Options{ + Reconciler: reconcile.Func(func(c context.Context, r reconcile.Request) (reconcile.Result, error) { + return reconcile.Result{}, nil + }), + }) + + if err != nil { + return nil, err + } + + err = c.Watch(&source.Kind{Type: &corev1.Service{}}, servHandler) + if err != nil { + return nil, err + } + + return c, nil +} + +// Create handles create events. +func (s *serviceEventHandler) Create(ce event.CreateEvent, wq workqueue.RateLimitingInterface) { + l := s.log.With().Str("name", "create-event-handler").Logger() + defer wq.Done(ce.Object) + + service, ok := ce.Object.(*corev1.Service) + if !ok { + return + } + + if service.Spec.Type != corev1.ServiceTypeLoadBalancer { + return + } + + annotations := filterAnnotations(service.Annotations, s.ServiceAnnotations) + if len(annotations) == 0 { + return + } + + ips, err := getIPsFromService(service) + if err != nil { + l.Err(err).Msg("error occurred while getting ips from service") + return + } + if len(ips) == 0 { + return + } + + for _, port := range service.Spec.Ports { + for _, ip := range ips { + + // Create an hashed name for this + toBeHashed := fmt.Sprintf("%s:%d", ip, port.Port) + h := sha256.New() + h.Write([]byte(toBeHashed)) + hash := hex.EncodeToString(h.Sum(nil)) + + // Only take the first 10 characters of the hashed name + name := fmt.Sprintf("%s:%s", service.Name, hash[:10]) + _ = name + // TODO: define the endpoint + } + } + + // TODO: check the namespace + // TODO: send event to listener that a new service has been created. +} + +// Update handles update events. +func (s *serviceEventHandler) Update(ue event.UpdateEvent, wq workqueue.RateLimitingInterface) { + l := s.log.With().Str("name", "update-event-handler").Logger() + defer wq.Done(ue.ObjectNew) + + curr, currok := ue.ObjectNew.(*corev1.Service) + old, oldok := ue.ObjectOld.(*corev1.Service) + if !currok || !oldok { + return + } + + currAnnotations := filterAnnotations(curr.Annotations, s.ServiceAnnotations) + oldAnnotations := filterAnnotations(old.Annotations, s.ServiceAnnotations) + + currIps, currErr := getIPsFromService(curr) + oldIps, oldErr := getIPsFromService(old) + if currErr != nil || oldErr != nil { + err := currErr + if err != nil { + err = oldErr + } + l.Err(oldErr).Msg("error occurred while getting ips from service") + return + } + + // ----------------------------------------------- + // Determine if this event should be skipped + // ----------------------------------------------- + + switch { + case curr.Spec.Type != corev1.ServiceTypeLoadBalancer && + old.Spec.Type != corev1.ServiceTypeLoadBalancer: + // Wasn't a LoadBalancer and still isn't + case len(oldAnnotations) == 0 && len(currAnnotations) == 0: + // Didn't and still hasn't required annotations. + case len(currIps) == 0 && len(oldIps) == 0: + // Wasn't DNS and still isn't + // TODO: case Namespace is not being watched: + return + } + + // ----------------------------------------------- + // Determine if we should remove this + // ----------------------------------------------- + + mustBeRemoved := func() (remove bool, reason string) { + switch { + case len(currIps) == 0: + remove, reason = true, "no ips found" + case curr.Spec.Type != corev1.ServiceTypeLoadBalancer: + remove, reason = true, "not a LoadBalancer" + case len(currAnnotations) == 0: + remove, reason = true, "no valid annotations" + case len(currIps) == 0: + remove, reason = true, "no valid hostnames/ips found" + } + + return + } + + if remove, reason := mustBeRemoved(); remove { + l.Info().Str("reason", reason).Msg("sending delete...") + // TODO + return + } + + // TODO +} + +// Delete handles delete events. +func (s *serviceEventHandler) Delete(de event.DeleteEvent, wq workqueue.RateLimitingInterface) { + l := s.log.With().Str("name", "delete-event-handler").Logger() + defer wq.Done(de.Object) + + service, ok := de.Object.(*corev1.Service) + if !ok { + return + } + + if service.Spec.Type != corev1.ServiceTypeLoadBalancer { + return + } + + annotations := filterAnnotations(service.Annotations, s.ServiceAnnotations) + if len(annotations) == 0 { + return + } + + ips, err := getIPsFromService(service) + if err != nil { + l.Err(err).Msg("error occurred while getting ips from service") + return + } + if len(ips) == 0 { + return + } + + // TODO: check the namespace + // TODO: send event to listener that a service has been deleted. +} + +// Generic handles generic events. +func (s *serviceEventHandler) Generic(ge event.GenericEvent, wq workqueue.RateLimitingInterface) { + // We don't really know what to do with generic events. + // We will just ignore this. + wq.Done(ge.Object) +} From 759649b19752c0845124eda3cf9c46e6e6adb6e7 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Wed, 22 Mar 2023 13:57:09 +0100 Subject: [PATCH 08/21] feat(serviceregistry): create event struct Signed-off-by: Elis Lulja --- pkg/serviceregistry/events_handler.go | 32 +++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 pkg/serviceregistry/events_handler.go diff --git a/pkg/serviceregistry/events_handler.go b/pkg/serviceregistry/events_handler.go new file mode 100644 index 0000000..76a3e0d --- /dev/null +++ b/pkg/serviceregistry/events_handler.go @@ -0,0 +1,32 @@ +// Copyright © 2023 Cisco +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// All rights reserved. + +package serviceregistry + +type EventType int + +const ( + EventCreate EventType = iota + EventUpdate + EventDelete +) + +type Event struct { + EventType + Object interface{} +} From e64e6b0521f7c46ab6b99d4370448df65ab19e37 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Wed, 22 Mar 2023 14:01:39 +0100 Subject: [PATCH 09/21] refactor(ctrl-utils): improve service checking Signed-off-by: Elis Lulja --- controllers/utils.go | 111 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 16 deletions(-) diff --git a/controllers/utils.go b/controllers/utils.go index cea4bd8..dc7a038 100644 --- a/controllers/utils.go +++ b/controllers/utils.go @@ -19,10 +19,13 @@ package controllers import ( + "crypto/sha256" + "encoding/hex" "fmt" "net" "strings" + serego "github.com/CloudNativeSDWAN/serego/api/core/types" corev1 "k8s.io/api/core/v1" ) @@ -68,7 +71,38 @@ func filterAnnotations(currentAnnotations map[string]string, filter []string) ma return filtered } -func shouldWatchLabel(labels map[string]string, watchAllByDefault bool) bool { +func getIPsFromService(service *corev1.Service) ([]string, error) { + ipsMap := map[string]bool{} + for _, externalIP := range service.Spec.ExternalIPs { + ipsMap[externalIP] = true + } + + // Get data from load balancers + for _, ing := range service.Status.LoadBalancer.Ingress { + if ing.IP != "" { + ipsMap[ing.IP] = true + } + + if ing.Hostname != "" { + resolvedIPs, err := net.LookupHost(ing.Hostname) + if err != nil { + return nil, err + } + + for _, resolvedIP := range resolvedIPs { + ipsMap[resolvedIP] = true + } + } + } + + ips := []string{} + for ip := range ipsMap { + ips = append(ips, ip) + } + return ips, nil +} + +func checkNsLabels(labels map[string]string, watchAllByDefault bool) bool { switch labels[watchLabel] { case watchEnabledLabel: return true @@ -79,25 +113,70 @@ func shouldWatchLabel(labels map[string]string, watchAllByDefault bool) bool { } } -func getIPsFromService(service *corev1.Service) ([]string, error) { - ips := []string{} - ips = append(ips, service.Spec.ExternalIPs...) +type checkServiceResult struct { + passed bool + reason string + err error + annotations map[string]string + ips []string + endpoints []*serego.Endpoint +} - // Get data from load balancers - for _, ing := range service.Status.LoadBalancer.Ingress { - if ing.IP != "" { - ips = append(ips, ing.IP) +func checkService(service *corev1.Service, annotationsToKeep []string) (result checkServiceResult) { + if service.Spec.Type != corev1.ServiceTypeLoadBalancer { + result.reason = "not a LoadBalancer" + return + } + + annotations := filterAnnotations(service.Annotations, annotationsToKeep) + if len(annotations) == 0 { + result.reason = "no valid annotations" + return + } + + ips, err := getIPsFromService(service) + if len(ips) == 0 { + result.reason = "no valid hostnames/ips found" + if err != nil { + result.err = err } - if ing.Hostname != "" { - if resolvedIPs, err := net.LookupHost(ing.Hostname); err != nil { - return nil, err - } else { - ips = append(ips, resolvedIPs...) - } + return + } + + result = checkServiceResult{ + passed: true, + annotations: annotations, + ips: ips, + endpoints: []*serego.Endpoint{}, + } + for _, port := range service.Spec.Ports { + for _, ip := range ips { + + // Create an hashed name for this + toBeHashed := fmt.Sprintf("%s:%d", ip, port.Port) + h := sha256.New() + h.Write([]byte(toBeHashed)) + hash := hex.EncodeToString(h.Sum(nil)) + + result.endpoints = append(result.endpoints, &serego.Endpoint{ + Namespace: service.Namespace, + Service: service.Name, + Name: fmt.Sprintf("%s-%s", service.Name, hash[:10]), + Address: ip, + Port: port.Port, + Metadata: annotations, + }) } - ips = append(ips, ing.IP) } - return ips, nil + return +} + +func getEndpointsMapFromSlice(endpoints []*serego.Endpoint) map[string]*serego.Endpoint { + epMap := map[string]*serego.Endpoint{} + for _, ep := range endpoints { + epMap[ep.Name] = ep + } + return epMap } From ad417cc1c1f17562274c4bf9cffb7de86d6e78c9 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Wed, 22 Mar 2023 14:03:26 +0100 Subject: [PATCH 10/21] refactor(ctrls): send events to channel Signed-off-by: Elis Lulja --- controllers/namespace.go | 112 +++++++++++++---- controllers/service.go | 253 ++++++++++++++++++++++++++------------- go.mod | 1 + go.sum | 2 + 4 files changed, 259 insertions(+), 109 deletions(-) diff --git a/controllers/namespace.go b/controllers/namespace.go index db8e057..4d03a25 100644 --- a/controllers/namespace.go +++ b/controllers/namespace.go @@ -19,11 +19,15 @@ package controllers import ( "context" + "time" + "github.com/CloudNativeSDWAN/cnwan-operator/pkg/serviceregistry" + serego "github.com/CloudNativeSDWAN/serego/api/core/types" "github.com/rs/zerolog" corev1 "k8s.io/api/core/v1" _ "k8s.io/client-go/plugin/pkg/client/auth" "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -41,12 +45,13 @@ const ( type ControllerOptions struct { WatchNamespacesByDefault bool ServiceAnnotations []string + EventsChan chan *serviceregistry.Event } type namespaceEventHandler struct { - // client - log zerolog.Logger - ControllerOptions + client client.Client + log zerolog.Logger + *ControllerOptions } func NewNamespaceController(mgr manager.Manager, opts *ControllerOptions, log zerolog.Logger) (controller.Controller, error) { @@ -57,7 +62,11 @@ func NewNamespaceController(mgr manager.Manager, opts *ControllerOptions, log ze return nil, ErrorInvalidControllerOptions } - nsHandler := &namespaceEventHandler{log: log} + nsHandler := &namespaceEventHandler{ + client: mgr.GetClient(), + log: log, + ControllerOptions: opts, + } c, err := controller.New(nsCtrlName, mgr, controller.Options{ Reconciler: reconcile.Func(func(c context.Context, r reconcile.Request) (reconcile.Result, error) { return reconcile.Result{}, nil @@ -78,18 +87,8 @@ func NewNamespaceController(mgr manager.Manager, opts *ControllerOptions, log ze // Create handles create events. func (n *namespaceEventHandler) Create(ce event.CreateEvent, wq workqueue.RateLimitingInterface) { - defer wq.Done(ce.Object) - - namespace, ok := ce.Object.(*corev1.Namespace) - if !ok { - return - } - - if !shouldWatchLabel(namespace.Labels, n.WatchNamespacesByDefault) { - return - } - - // TODO: send event to listener that a new namespace has been created. + // The namespace is created once an appropriate service appears. + wq.Done(ce.Object) } // Update handles update events. @@ -102,16 +101,16 @@ func (n *namespaceEventHandler) Update(ue event.UpdateEvent, wq workqueue.RateLi return } - watchedBefore := shouldWatchLabel(curr.Labels, n.WatchNamespacesByDefault) - watchNow := shouldWatchLabel(old.Labels, n.WatchNamespacesByDefault) + watchNow := checkNsLabels(curr.Labels, n.WatchNamespacesByDefault) + watchedBefore := checkNsLabels(old.Labels, n.WatchNamespacesByDefault) switch { - case !watchedBefore && !watchNow: + case watchedBefore && watchNow: return - case !watchedBefore && watchNow: - // TODO: send create ns, send create for all services inside it case watchedBefore && !watchNow: - // TODO: send delete for all services inside it, send delete ns + n.handleUpdateEvent(curr, serviceregistry.EventDelete) + case !watchedBefore && watchNow: + n.handleUpdateEvent(curr, serviceregistry.EventCreate) } } @@ -124,11 +123,76 @@ func (n *namespaceEventHandler) Delete(de event.DeleteEvent, wq workqueue.RateLi return } - if !shouldWatchLabel(namespace.Labels, n.WatchNamespacesByDefault) { + if !checkNsLabels(namespace.Labels, n.WatchNamespacesByDefault) { return } - // TODO: send event to listener that a namespace has been deleted. + n.handleUpdateEvent(namespace, serviceregistry.EventDelete) +} + +func (n *namespaceEventHandler) handleUpdateEvent(namespace *corev1.Namespace, eventType serviceregistry.EventType) { + ctx, canc := context.WithTimeout(context.Background(), 10*time.Second) + defer canc() + + services := corev1.ServiceList{} + if err := n.client.List(ctx, &services, &client.ListOptions{ + Namespace: namespace.Name, + }); err != nil { + n.log.Err(err).Str("namespace", namespace.Name). + Msg("cannot retrieve list of services inside namespace") + return + } + + // Inline function definitions for sending the namespace and service + sendNsEvent := func() { + n.EventsChan <- &serviceregistry.Event{ + EventType: eventType, + Object: &serego.Namespace{ + Name: namespace.Name, + }, + } + } + switch eventType { + case serviceregistry.EventCreate: + sendNsEvent() + case serviceregistry.EventDelete: + defer sendNsEvent() + } + + sendServiceEvent := func(name string) { + n.EventsChan <- &serviceregistry.Event{ + EventType: eventType, + Object: &serego.Service{ + Namespace: namespace.Name, + Name: name, + }, + } + } + + for _, service := range services.Items { + checkedService := checkService(&service, n.ServiceAnnotations) + if !checkedService.passed { + continue + } + + func() { + // using an anonymous function, so we can defer events + // if needed. + switch eventType { + case serviceregistry.EventCreate: + sendServiceEvent(service.Name) + case serviceregistry.EventDelete: + defer sendServiceEvent(service.Name) + } + + for _, endpoint := range checkedService.endpoints { + n.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventDelete, + Object: endpoint, + } + } + }() + } } // Generic handles generic events. diff --git a/controllers/service.go b/controllers/service.go index 9d2d914..9f33a7f 100644 --- a/controllers/service.go +++ b/controllers/service.go @@ -19,14 +19,16 @@ package controllers import ( "context" - "crypto/sha256" - "encoding/hex" - "fmt" + "time" + "github.com/CloudNativeSDWAN/cnwan-operator/pkg/serviceregistry" + serego "github.com/CloudNativeSDWAN/serego/api/core/types" "github.com/rs/zerolog" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" _ "k8s.io/client-go/plugin/pkg/client/auth" "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -39,9 +41,9 @@ const ( ) type serviceEventHandler struct { - // client - log zerolog.Logger - ControllerOptions + client client.Client + log zerolog.Logger + *ControllerOptions } func NewServiceController(mgr manager.Manager, opts *ControllerOptions, log zerolog.Logger) (controller.Controller, error) { @@ -52,8 +54,12 @@ func NewServiceController(mgr manager.Manager, opts *ControllerOptions, log zero return nil, ErrorInvalidControllerOptions } - servHandler := &namespaceEventHandler{log: log} - c, err := controller.New(nsCtrlName, mgr, controller.Options{ + servHandler := &serviceEventHandler{ + client: mgr.GetClient(), + log: log, + ControllerOptions: opts, + } + c, err := controller.New(servCtrlName, mgr, controller.Options{ Reconciler: reconcile.Func(func(c context.Context, r reconcile.Request) (reconcile.Result, error) { return reconcile.Result{}, nil }), @@ -81,42 +87,54 @@ func (s *serviceEventHandler) Create(ce event.CreateEvent, wq workqueue.RateLimi return } - if service.Spec.Type != corev1.ServiceTypeLoadBalancer { - return - } + l = l.With().Str("name", types.NamespacedName{ + Namespace: service.Namespace, + Name: service.Name, + }.String()).Logger() - annotations := filterAnnotations(service.Annotations, s.ServiceAnnotations) - if len(annotations) == 0 { - return - } + watchNs, err := s.checkParentNamespace(service) + if !watchNs { + if err != nil { + l.Err(err).Msg("cannot check parent namespace") + } - ips, err := getIPsFromService(service) - if err != nil { - l.Err(err).Msg("error occurred while getting ips from service") return } - if len(ips) == 0 { + + checkedService := checkService(service, s.ServiceAnnotations) + if !checkedService.passed { + if checkedService.err != nil { + l.Err(err).Msg("cannot check service") + } + return } - for _, port := range service.Spec.Ports { - for _, ip := range ips { + // Send an event to create the namespace. NOTE: we do this because we have + // no idea whether the namespace controller sent this before us. Se we + // disabled the namespace controller from sending Create events, and we let + // the service controller do that. + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventCreate, + Object: &serego.Namespace{ + Name: service.Namespace, + }, + } - // Create an hashed name for this - toBeHashed := fmt.Sprintf("%s:%d", ip, port.Port) - h := sha256.New() - h.Write([]byte(toBeHashed)) - hash := hex.EncodeToString(h.Sum(nil)) + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventCreate, + Object: &serego.Service{ + Name: service.Name, + Namespace: service.Namespace, + }, + } - // Only take the first 10 characters of the hashed name - name := fmt.Sprintf("%s:%s", service.Name, hash[:10]) - _ = name - // TODO: define the endpoint + for _, ep := range checkedService.endpoints { + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventCreate, + Object: ep, } } - - // TODO: check the namespace - // TODO: send event to listener that a new service has been created. } // Update handles update events. @@ -130,67 +148,109 @@ func (s *serviceEventHandler) Update(ue event.UpdateEvent, wq workqueue.RateLimi return } - currAnnotations := filterAnnotations(curr.Annotations, s.ServiceAnnotations) - oldAnnotations := filterAnnotations(old.Annotations, s.ServiceAnnotations) + l = l.With().Str("name", types.NamespacedName{ + Namespace: curr.Namespace, + Name: curr.Name, + }.String()).Logger() - currIps, currErr := getIPsFromService(curr) - oldIps, oldErr := getIPsFromService(old) - if currErr != nil || oldErr != nil { - err := currErr + watchNs, err := s.checkParentNamespace(curr) + if !watchNs { if err != nil { - err = oldErr + l.Err(err).Msg("cannot check parent namespace") } - l.Err(oldErr).Msg("error occurred while getting ips from service") + return } - // ----------------------------------------------- - // Determine if this event should be skipped - // ----------------------------------------------- + currChecked := checkService(curr, s.ServiceAnnotations) + oldChecked := checkService(old, s.ServiceAnnotations) - switch { - case curr.Spec.Type != corev1.ServiceTypeLoadBalancer && - old.Spec.Type != corev1.ServiceTypeLoadBalancer: - // Wasn't a LoadBalancer and still isn't - case len(oldAnnotations) == 0 && len(currAnnotations) == 0: - // Didn't and still hasn't required annotations. - case len(currIps) == 0 && len(oldIps) == 0: - // Wasn't DNS and still isn't - // TODO: case Namespace is not being watched: + if currChecked.err != nil || oldChecked.err != nil { + err := currChecked.err + if err != nil { + err = oldChecked.err + } + l.Err(err).Msg("error occurred while getting ips from service") return } - // ----------------------------------------------- - // Determine if we should remove this - // ----------------------------------------------- - - mustBeRemoved := func() (remove bool, reason string) { - switch { - case len(currIps) == 0: - remove, reason = true, "no ips found" - case curr.Spec.Type != corev1.ServiceTypeLoadBalancer: - remove, reason = true, "not a LoadBalancer" - case len(currAnnotations) == 0: - remove, reason = true, "no valid annotations" - case len(currIps) == 0: - remove, reason = true, "no valid hostnames/ips found" + // Easiest cases + switch { + case !oldChecked.passed && !currChecked.passed: + return + case oldChecked.passed && !currChecked.passed: + l.Info().Str("reason", currChecked.reason).Msg("sending delete...") + + for _, ep := range oldChecked.endpoints { + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventDelete, + Object: ep, + } + } + + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventDelete, + Object: &serego.Service{ + Name: old.Name, + Namespace: old.Namespace, + }, } return - } + case !oldChecked.passed && currChecked.passed: + l.Info().Msg("sending create...") + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventCreate, + Object: &serego.Service{ + Name: curr.Name, + Namespace: curr.Namespace, + }, + } + + for _, ep := range currChecked.endpoints { + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventCreate, + Object: ep, + } + } - if remove, reason := mustBeRemoved(); remove { - l.Info().Str("reason", reason).Msg("sending delete...") - // TODO return } - // TODO + // Check what is changed + oldEndpoints := getEndpointsMapFromSlice(oldChecked.endpoints) + currEndpoints := getEndpointsMapFromSlice(currChecked.endpoints) + + // Check what must be removed, updated or created + for _, ep := range oldEndpoints { + currEp := currEndpoints[ep.Name] + + if currEp == nil { + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventDelete, + Object: ep, + } + } else { + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventUpdate, + Object: currEp, + } + } + } + + for _, ep := range currEndpoints { + if _, exists := currEndpoints[ep.Name]; !exists { + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventCreate, + Object: ep, + } + } + } } // Delete handles delete events. func (s *serviceEventHandler) Delete(de event.DeleteEvent, wq workqueue.RateLimitingInterface) { - l := s.log.With().Str("name", "delete-event-handler").Logger() + l := s.log.With().Str("handler", "service-delete-event-handler").Logger() defer wq.Done(de.Object) service, ok := de.Object.(*corev1.Service) @@ -198,26 +258,49 @@ func (s *serviceEventHandler) Delete(de event.DeleteEvent, wq workqueue.RateLimi return } - if service.Spec.Type != corev1.ServiceTypeLoadBalancer { + l = l.With().Str("name", types.NamespacedName{ + Namespace: service.Namespace, + Name: service.Name, + }.String()).Logger() + + watchNs, err := s.checkParentNamespace(service) + if !watchNs { + if err != nil { + l.Err(err).Msg("cannot check parent namespace") + } + return } - annotations := filterAnnotations(service.Annotations, s.ServiceAnnotations) - if len(annotations) == 0 { - return + checkedService := checkService(service, s.ServiceAnnotations) + + for _, ep := range checkedService.endpoints { + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventDelete, + Object: ep, + } } - ips, err := getIPsFromService(service) - if err != nil { - l.Err(err).Msg("error occurred while getting ips from service") - return + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventDelete, + Object: &serego.Service{ + Name: service.Name, + Namespace: service.Namespace, + }, } - if len(ips) == 0 { - return +} + +func (s *serviceEventHandler) checkParentNamespace(service *corev1.Service) (bool, error) { + ctx, canc := context.WithTimeout(context.Background(), 10*time.Second) + defer canc() + + var namespace corev1.Namespace + if err := s.client. + Get(ctx, types.NamespacedName{Name: service.Namespace}, &namespace); err != nil { + return false, err } - // TODO: check the namespace - // TODO: send event to listener that a service has been deleted. + return checkNsLabels(namespace.Labels, s.WatchNamespacesByDefault), nil } // Generic handles generic events. diff --git a/go.mod b/go.mod index 3d331fa..1a31234 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( cloud.google.com/go/compute/metadata v0.2.3 cloud.google.com/go/servicedirectory v1.8.0 + github.com/CloudNativeSDWAN/serego/api v0.1.0 github.com/aws/aws-sdk-go v1.44.221 github.com/aws/aws-sdk-go-v2 v1.17.6 github.com/aws/aws-sdk-go-v2/config v1.18.17 diff --git a/go.sum b/go.sum index 8f0d1d5..efb2b5e 100644 --- a/go.sum +++ b/go.sum @@ -37,6 +37,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 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/CloudNativeSDWAN/serego/api v0.1.0 h1:pf/mCCOLc68yPkCBvTptb6SRn4g54UWlTGhKWPkZ+mM= +github.com/CloudNativeSDWAN/serego/api v0.1.0/go.mod h1:oPBA8qDggoskmReFPd/oWidYZYqduBX+VN4oB9XL7G4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= From b64288f19495752769e0f5f7311ac18a1c09b01e Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Wed, 22 Mar 2023 15:43:30 +0100 Subject: [PATCH 11/21] feat(event-handler): create namespace worker Signed-off-by: Elis Lulja --- pkg/serviceregistry/namespace_worker.go | 64 +++++++++++++++++++++++++ pkg/serviceregistry/utils.go | 34 +++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 pkg/serviceregistry/namespace_worker.go create mode 100644 pkg/serviceregistry/utils.go diff --git a/pkg/serviceregistry/namespace_worker.go b/pkg/serviceregistry/namespace_worker.go new file mode 100644 index 0000000..036aad3 --- /dev/null +++ b/pkg/serviceregistry/namespace_worker.go @@ -0,0 +1,64 @@ +// Copyright © 2023 Cisco +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// All rights reserved. + +package serviceregistry + +import ( + "context" + "time" + + serego "github.com/CloudNativeSDWAN/serego/api/core/types" + "github.com/rs/zerolog" +) + +type namespaceWorkerData struct { + worker *namespaceWorker + ctx context.Context + canc context.CancelFunc + lastEvent time.Time +} + +type namespaceWorker struct { + log zerolog.Logger + eventsChan chan *Event +} + +func (n *namespaceWorker) handleNamespacedEvents(ctx context.Context) error { + l := n.log.With().Logger() + l.Info().Msg("worker waiting for events for this namespace...") + + for { + select { + case <-ctx.Done(): + l.Info().Msg("received stop from manager: exiting...") + return nil + case event := <-n.eventsChan: + switch o := event.Object.(type) { + case *serego.Namespace: + // TODO: handle namespace event + l.Info().Str("event type", string(event.EventType)).Str("name", o.Name).Msg("received namespace event") + case *serego.Service: + // TODO: handle service event + l.Info().Str("event type", string(event.EventType)).Str("name", o.Namespace+"/"+o.Name).Msg("received service event") + case *serego.Endpoint: + // TODO: handle endpoint event + l.Info().Str("event type", string(event.EventType)).Str("name", o.Namespace+"/"+o.Service+"/"+o.Name).Msg("received endpoint event") + } + } + } +} diff --git a/pkg/serviceregistry/utils.go b/pkg/serviceregistry/utils.go new file mode 100644 index 0000000..34df8fe --- /dev/null +++ b/pkg/serviceregistry/utils.go @@ -0,0 +1,34 @@ +// Copyright © 2023 Cisco +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// All rights reserved. + +package serviceregistry + +import serego "github.com/CloudNativeSDWAN/serego/api/core/types" + +func getNamespaceNameFromEventObject(event *Event) string { + switch parsedObject := event.Object.(type) { + case *serego.Namespace: + return parsedObject.Name + case *serego.Service: + return parsedObject.Namespace + case *serego.Endpoint: + return parsedObject.Namespace + default: + return "" + } +} From 4b04a0a6e18e0f158f5cf72ebd5a2efe9a3686db Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Wed, 22 Mar 2023 15:47:02 +0100 Subject: [PATCH 12/21] feat(events-handler): create events handler Signed-off-by: Elis Lulja --- pkg/serviceregistry/events_handler.go | 131 +++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 4 deletions(-) diff --git a/pkg/serviceregistry/events_handler.go b/pkg/serviceregistry/events_handler.go index 76a3e0d..61ba352 100644 --- a/pkg/serviceregistry/events_handler.go +++ b/pkg/serviceregistry/events_handler.go @@ -18,15 +18,138 @@ package serviceregistry -type EventType int +import ( + "context" + "sync" + "time" + + "github.com/rs/zerolog" +) + +type EventType string const ( - EventCreate EventType = iota - EventUpdate - EventDelete + EventCreate EventType = "create" + EventUpdate EventType = "update" + EventDelete EventType = "delete" +) + +const ( + maximumIdleDuration = 5 * time.Minute ) type Event struct { EventType Object interface{} } + +type EventHandler struct { + workers map[string]*namespaceWorkerData + waitGroup sync.WaitGroup + log zerolog.Logger +} + +func NewEventHandler(log zerolog.Logger) *EventHandler { + return &EventHandler{ + workers: map[string]*namespaceWorkerData{}, + waitGroup: sync.WaitGroup{}, + log: log, + } +} + +func (e *EventHandler) WatchForEvents(mainCtx context.Context, eventsChannel chan *Event) error { + l := e.log.With().Logger() + l.Info().Msg("watching for events from the cluster...") + + cleanUpTicker := time.NewTicker(time.Minute) + for { + select { + + case <-mainCtx.Done(): + l := e.log.With().Str("from", "event handler").Logger() + l.Info().Msg("cancel requested") + if len(e.workers) == 0 { + return nil + } + + l.Info().Msg("propagating cancel to all namespace workers...") + + for _, nsWorker := range e.workers { + nsWorker.canc() + } + + l.Debug().Msg("waiting for all namespace workers to finish...") + e.waitGroup.Wait() + l.Info().Msg("all namespace workers exited: goodbye!") + return nil + + case event := <-eventsChannel: + l := e.log.With().Str("from", "event-dispatcher").Logger() + namespaceName := getNamespaceNameFromEventObject(event) + + if namespaceName == "" { + l.Warn().Msg("could not find namespace name: skipping...") + continue + } + + l.Info().Str("namespace", namespaceName). + Msg("received event: retrieving namespace worker in " + + "charge of it...") + + nsWorker := e.getOrCreateNamespaceWorker(mainCtx, namespaceName) + + l.Info().Msg("dispatching event to namespace worker...") + + nsWorker.worker.eventsChan <- event + nsWorker.lastEvent = time.Now() + + case <-cleanUpTicker.C: + l := e.log.With().Str("from", "worker-manager").Logger() + + now := time.Now() + toRemove := []string{} + + for name, worker := range e.workers { + if now.Sub(worker.lastEvent) > maximumIdleDuration { + l.Info().Str("namespace", name). + Msg("worker exceeded maximum idle time: signaling stop...") + worker.canc() + toRemove = append(toRemove, name) + } + } + + for _, workerToRemove := range toRemove { + delete(e.workers, workerToRemove) + } + } + } +} + +func (e *EventHandler) getOrCreateNamespaceWorker(mainCtx context.Context, name string) *namespaceWorkerData { + l := e.log.With().Str("namespace", name).Logger() + + nsWorker, exists := e.workers[name] + if exists { + l.Debug().Msg("worker already running") + return nsWorker + } + + l.Debug().Msg("creating namespace worker...") + data := &namespaceWorkerData{ + worker: &namespaceWorker{ + log: e.log.With().Str("worker", name+"-event-handler").Logger(), + eventsChan: make(chan *Event, 25), + }, + } + data.ctx, data.canc = context.WithCancel(mainCtx) + e.workers[name] = data + + // Add it to the wait group so we can successfully wait for it to finish + e.waitGroup.Add(1) + go func() { + defer e.waitGroup.Done() + data.worker.handleNamespacedEvents(data.ctx) + }() + + return data +} From 9ec868192a3919e03492e3b5f0133c78c30d6b91 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Wed, 22 Mar 2023 15:50:24 +0100 Subject: [PATCH 13/21] refactor(ctrls): move to `pkg` Signed-off-by: Elis Lulja --- controllers/namespace_controller.go | 182 ------------------ controllers/service_controller.go | 142 -------------- controllers/suite_test.go | 85 -------- main.go | 115 +++++++---- {controllers => pkg/controllers}/doc.go | 0 {controllers => pkg/controllers}/errors.go | 0 {controllers => pkg/controllers}/manager.go | 0 {controllers => pkg/controllers}/namespace.go | 0 {controllers => pkg/controllers}/service.go | 0 {controllers => pkg/controllers}/utils.go | 0 .../controllers}/utils_test.go | 0 11 files changed, 79 insertions(+), 445 deletions(-) delete mode 100644 controllers/namespace_controller.go delete mode 100644 controllers/service_controller.go delete mode 100644 controllers/suite_test.go rename {controllers => pkg/controllers}/doc.go (100%) rename {controllers => pkg/controllers}/errors.go (100%) rename {controllers => pkg/controllers}/manager.go (100%) rename {controllers => pkg/controllers}/namespace.go (100%) rename {controllers => pkg/controllers}/service.go (100%) rename {controllers => pkg/controllers}/utils.go (100%) rename {controllers => pkg/controllers}/utils_test.go (100%) diff --git a/controllers/namespace_controller.go b/controllers/namespace_controller.go deleted file mode 100644 index 7902898..0000000 --- a/controllers/namespace_controller.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright © 2020, 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package controllers - -import ( - "context" - "fmt" - "strings" - "sync" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - watchLabel string = "operator.cnwan.io/watch" -) - -// NamespaceReconciler reconciles a Namespace object -type NamespaceReconciler struct { - client.Client - Log logr.Logger - Scheme *runtime.Scheme - WatchNamespacesByDefault bool - AllowedAnnotations []string - nsLastConf map[string]bool - lock sync.Mutex - ServRegBroker *sr.Broker -} - -// +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=namespaces/status,verbs=get;update;patch - -// Reconcile checks the changes in a service and reflects those changes in the service registry -func (r *NamespaceReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - ctx := context.Background() - l := r.Log.WithValues("namespace", req.NamespacedName) - - // Get the namespace - var ns corev1.Namespace - deleted := false - - err := r.Get(ctx, req.NamespacedName, &ns) - if err != nil { - if client.IgnoreNotFound(err) != nil { - l.Error(err, "unable to fetch the namespace") - // we'll ignore not-found errors, since they can't be fixed by an immediate - // requeue (we'll need to wait for a new notification), and we can get them - // on deleted requests. - return ctrl.Result{}, client.IgnoreNotFound(err) - } - - l.V(0).Info("namespace was deleted") - ns.Name = req.Name - ns.Namespace = req.Namespace - deleted = true - } - - if r.ServRegBroker == nil { - l.Error(fmt.Errorf("%s", "service registry broker is nil"), "cannot handle namespace") - return ctrl.Result{}, nil - } - - if deleted { - // If this namespace was deleted, there is no point in loading - // services: you won't find anything there. - // So let's save ourselves some computation and just go straight to - // business then. - if err := r.ServRegBroker.RemoveNs(ns.Name, true); err != nil { - l.Error(err, "error while deleting service") - } - - r.lock.Lock() - defer r.lock.Unlock() - - delete(r.nsLastConf, ns.Name) - return ctrl.Result{}, nil - } - - change, nsIsWatched := func() (bool, bool) { - var currentlyWatched bool - switch strings.ToLower(ns.Labels[watchLabel]) { - case "enabled": - currentlyWatched = true - case "disabled": - currentlyWatched = false - default: - currentlyWatched = r.WatchNamespacesByDefault - } - - r.lock.Lock() - defer r.lock.Unlock() - previouslyWatched, existed := r.nsLastConf[ns.Name] - if !existed { - previouslyWatched = r.WatchNamespacesByDefault - } - - changed := currentlyWatched != previouslyWatched - r.nsLastConf[ns.Name] = currentlyWatched - return changed, currentlyWatched - }() - if !change { - return ctrl.Result{}, nil - } - - var servList corev1.ServiceList - if err := r.List(ctx, &servList, &client.ListOptions{Namespace: ns.Name}); err != nil { - l.Error(err, "error while getting services") - return ctrl.Result{}, err - } - - // First, check the services - for _, serv := range servList.Items { - if !nsIsWatched { - if err := r.ServRegBroker.RemoveServ(serv.Namespace, serv.Name, true); err != nil { - l.Error(err, "error while deleting service") - } - } else { - // Get the data in our simpler format - // Note: as of now, we are not copying any annotations from a namespace - serv.Annotations = filterAnnotations(serv.Annotations, r.AllowedAnnotations) - nsData, servData, endpList, err := r.ServRegBroker.Reg.ExtractData(&ns, &serv) - if err != nil { - l.WithValues("serv-name", servData.Name).Error(err, "error while extracting data from the namespace and service") - return ctrl.Result{}, nil - } - nsData.Metadata = map[string]string{} - - if _, err := r.ServRegBroker.ManageNs(nsData); err != nil { - l.WithValues("ns-name", nsData.Name).Error(err, "error while processing namespace change") - return ctrl.Result{}, nil - } - if len(servData.Metadata) > 0 && len(endpList) > 0 { - if _, err := r.ServRegBroker.ManageServ(servData); err != nil { - l.WithValues("serv-name", servData.Name).Error(err, "error while updating service") - continue - } - if _, err := r.ServRegBroker.ManageServEndps(servData.NsName, servData.Name, endpList); err != nil { - l.WithValues("serv-name", servData.Name).Error(err, "an error occurred while processing service's endpoints") - continue - } - } - } - } - - if !nsIsWatched { - if err := r.ServRegBroker.RemoveNs(ns.Name, true); err != nil { - l.Error(err, "error while deleting service") - } - } - - return ctrl.Result{}, nil -} - -// SetupWithManager ... -func (r *NamespaceReconciler) SetupWithManager(mgr ctrl.Manager) error { - r.nsLastConf = map[string]bool{} - - return ctrl.NewControllerManagedBy(mgr). - For(&corev1.Namespace{}). - Complete(r) -} diff --git a/controllers/service_controller.go b/controllers/service_controller.go deleted file mode 100644 index fab9cee..0000000 --- a/controllers/service_controller.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright © 2020, 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package controllers - -import ( - "context" - "fmt" - "strings" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -// ServiceReconciler reconciles a Service object -type ServiceReconciler struct { - client.Client - Log logr.Logger - Scheme *runtime.Scheme - ServRegBroker *sr.Broker - WatchNamespacesByDefault bool - AllowedAnnotations []string -} - -// +kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=services/status,verbs=get;update;patch - -// Reconcile checks the changes in a service and reflects those changes in the service registry -func (r *ServiceReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - ctx := context.Background() - l := r.Log.WithValues("service", req.NamespacedName) - deleted := false - - // Get the service - var service corev1.Service - - err := r.Get(ctx, req.NamespacedName, &service) - if err != nil { - if client.IgnoreNotFound(err) != nil { - l.Error(err, "unable to fetch the service") - // we'll ignore not-found errors, since they can't be fixed by an immediate - // requeue (we'll need to wait for a new notification), and we can get them - // on deleted requests. - return ctrl.Result{}, client.IgnoreNotFound(err) - } - - l.V(0).Info("service was deleted") - service.Name = req.Name - service.Namespace = req.Namespace - deleted = true - } - - if r.ServRegBroker == nil { - l.Error(fmt.Errorf("%s", "service registry broker is nil"), "cannot handle service") - return ctrl.Result{}, nil - } - - // Get the namespace - var ns corev1.Namespace - if err := r.Get(ctx, types.NamespacedName{Name: service.Namespace}, &ns); err != nil { - l.Error(err, "error occurred while trying to get namespace") - return ctrl.Result{}, err - } - - var shouldWatchNs bool - switch strings.ToLower(ns.Labels[watchLabel]) { - case "enabled": - shouldWatchNs = true - case "disabled": - shouldWatchNs = false - default: - shouldWatchNs = r.WatchNamespacesByDefault - } - - if !shouldWatchNs { - l.V(1).Info("ignoring service as namespace is not in the allow list") - return ctrl.Result{}, nil - } - - // Get the data in our simpler format - // Note: as of now, we are not copying any annotations from a namespace - service.Annotations = filterAnnotations(service.Annotations, r.AllowedAnnotations) - nsData, servData, endpList, err := r.ServRegBroker.Reg.ExtractData(&ns, &service) - if err != nil { - l.Error(err, "error while getting data from the namespace and service") - return ctrl.Result{}, nil - } - - // We don't support metadata on namespaces right now - nsData.Metadata = map[string]string{} - - if !deleted && len(endpList) > 0 && len(servData.Metadata) > 0 { - if _, err := r.ServRegBroker.ManageNs(nsData); err != nil { - l.WithValues("ns-name", nsData.Name).Error(err, "an error occurred while processing the namespace") - return ctrl.Result{}, nil - } - if _, err := r.ServRegBroker.ManageServ(servData); err != nil { - l.WithValues("serv-name", nsData.Name).Error(err, "an error occurred while processing the service") - return ctrl.Result{}, nil - } - if _, err := r.ServRegBroker.ManageServEndps(nsData.Name, servData.Name, endpList); err != nil { - l.WithValues("serv-name", nsData.Name).Error(err, "an error occurred while processing service's endpoints") - return ctrl.Result{}, nil - } - return ctrl.Result{}, nil - } - - if err := r.ServRegBroker.RemoveServ(ns.Name, service.Name, true); err != nil { - l.WithValues("serv-name", nsData.Name).Error(err, "an error occurred while processing service deletion") - return ctrl.Result{}, nil - } - - return ctrl.Result{}, nil -} - -// SetupWithManager ... -func (r *ServiceReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&corev1.Service{}). - Complete(r) -} diff --git a/controllers/suite_test.go b/controllers/suite_test.go deleted file mode 100644 index 5a91fc7..0000000 --- a/controllers/suite_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package controllers - -import ( - "path/filepath" - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - corev1 "k8s.io/api/core/v1" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - "sigs.k8s.io/controller-runtime/pkg/envtest/printer" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - // +kubebuilder:scaffold:imports -) - -// These tests use Ginkgo (BDD-style Go testing framework). Refer to -// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. - -var cfg *rest.Config -var k8sClient client.Client -var testEnv *envtest.Environment - -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "Controller Suite", - []Reporter{printer.NewlineReporter{}}) -} - -var _ = BeforeSuite(func(done Done) { - logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) - - By("bootstrapping test environment") - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, - } - - var err error - cfg, err = testEnv.Start() - Expect(err).ToNot(HaveOccurred()) - Expect(cfg).ToNot(BeNil()) - - err = corev1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - - err = corev1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - - // +kubebuilder:scaffold:scheme - - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) - Expect(err).ToNot(HaveOccurred()) - Expect(k8sClient).ToNot(BeNil()) - - close(done) -}, 60) - -var _ = AfterSuite(func() { - By("tearing down the test environment") - err := testEnv.Stop() - Expect(err).ToNot(HaveOccurred()) -}) diff --git a/main.go b/main.go index 67d52cc..28d52c3 100644 --- a/main.go +++ b/main.go @@ -22,15 +22,19 @@ import ( "context" "fmt" "os" + "os/signal" + "syscall" - "github.com/CloudNativeSDWAN/cnwan-operator/controllers" "github.com/CloudNativeSDWAN/cnwan-operator/internal/types" "github.com/CloudNativeSDWAN/cnwan-operator/internal/utils" "github.com/CloudNativeSDWAN/cnwan-operator/pkg/cluster" + "github.com/CloudNativeSDWAN/cnwan-operator/pkg/controllers" + "github.com/CloudNativeSDWAN/cnwan-operator/pkg/serviceregistry" sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry/aws/cloudmap" "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry/etcd" sd "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry/gcloud/servicedirectory" + "github.com/rs/zerolog" clientv3 "go.etcd.io/etcd/client/v3" "gopkg.in/yaml.v3" corev1 "k8s.io/api/core/v1" @@ -209,46 +213,85 @@ func run() (int, error) { return CannotGetBroker, fmt.Errorf("cannot get service registry broker: %w", err) } - //-------------------------------------- - // Init manager - //-------------------------------------- + _ = srBroker - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - LeaderElection: false, - MetricsBindAddress: "0", - }) + log := zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger() + manager, err := controllers.NewManager("") if err != nil { - return CannotGetControllerManager, fmt.Errorf("cannot create controller manager: %w", err) - } - - if err = (&controllers.ServiceReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("Service"), - Scheme: mgr.GetScheme(), - ServRegBroker: srBroker, - WatchNamespacesByDefault: settings.WatchNamespacesByDefault, - AllowedAnnotations: settings.Service.Annotations, - }).SetupWithManager(mgr); err != nil { - return CannotCreateServiceController, fmt.Errorf("cannot create service controller: %w", err) + log.Err(err).Msg("cannot create manager") + return 1, err } - if err = (&controllers.NamespaceReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("Namespace"), - Scheme: mgr.GetScheme(), - ServRegBroker: srBroker, - WatchNamespacesByDefault: settings.WatchNamespacesByDefault, - AllowedAnnotations: settings.Service.Annotations, - }).SetupWithManager(mgr); err != nil { - return CannotCreateNamespaceController, fmt.Errorf("cannot create namespace controller: %w", err) - } - // +kubebuilder:scaffold:builder + stopChan := make(chan os.Signal, 1) + signal.Notify(stopChan, syscall.SIGINT, syscall.SIGTERM) + watchCtx, watchCanc := context.WithCancel(ctx) + exitChan := make(chan struct{}) + go func() { + defer close(exitChan) + eventsChan := make(chan *serviceregistry.Event, 100) + eventHandler := serviceregistry.NewEventHandler(log) + + go func() { + eventHandler.WatchForEvents(watchCtx, eventsChan) + close(exitChan) + }() + + controllers.NewNamespaceController(manager, &controllers.ControllerOptions{ + EventsChan: eventsChan, + ServiceAnnotations: settings.Service.Annotations, + }, log) + controllers.NewServiceController(manager, &controllers.ControllerOptions{ + EventsChan: eventsChan, + ServiceAnnotations: settings.Service.Annotations, + }, log) + + manager.Start(ctx) + fmt.Println("closing") + }() + + <-stopChan + watchCanc() + <-exitChan + //-------------------------------------- + // Init manager + //-------------------------------------- - setupLog.Info("starting controller manager...") - if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { - return CannotRunControllerManager, fmt.Errorf("cannot run controller manager: %w", err) - } + // mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + // Scheme: scheme, + // LeaderElection: false, + // MetricsBindAddress: "0", + // }) + // if err != nil { + // return CannotGetControllerManager, fmt.Errorf("cannot create controller manager: %w", err) + // } + + // if err = (&controllers.ServiceReconciler{ + // Client: mgr.GetClient(), + // Log: ctrl.Log.WithName("controllers").WithName("Service"), + // Scheme: mgr.GetScheme(), + // ServRegBroker: srBroker, + // WatchNamespacesByDefault: settings.WatchNamespacesByDefault, + // AllowedAnnotations: settings.Service.Annotations, + // }).SetupWithManager(mgr); err != nil { + // return CannotCreateServiceController, fmt.Errorf("cannot create service controller: %w", err) + // } + + // if err = (&controllers.NamespaceReconciler{ + // Client: mgr.GetClient(), + // Log: ctrl.Log.WithName("controllers").WithName("Namespace"), + // Scheme: mgr.GetScheme(), + // ServRegBroker: srBroker, + // WatchNamespacesByDefault: settings.WatchNamespacesByDefault, + // AllowedAnnotations: settings.Service.Annotations, + // }).SetupWithManager(mgr); err != nil { + // return CannotCreateNamespaceController, fmt.Errorf("cannot create namespace controller: %w", err) + // } + // // +kubebuilder:scaffold:builder + + // setupLog.Info("starting controller manager...") + // if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + // return CannotRunControllerManager, fmt.Errorf("cannot run controller manager: %w", err) + // } return Success, nil } diff --git a/controllers/doc.go b/pkg/controllers/doc.go similarity index 100% rename from controllers/doc.go rename to pkg/controllers/doc.go diff --git a/controllers/errors.go b/pkg/controllers/errors.go similarity index 100% rename from controllers/errors.go rename to pkg/controllers/errors.go diff --git a/controllers/manager.go b/pkg/controllers/manager.go similarity index 100% rename from controllers/manager.go rename to pkg/controllers/manager.go diff --git a/controllers/namespace.go b/pkg/controllers/namespace.go similarity index 100% rename from controllers/namespace.go rename to pkg/controllers/namespace.go diff --git a/controllers/service.go b/pkg/controllers/service.go similarity index 100% rename from controllers/service.go rename to pkg/controllers/service.go diff --git a/controllers/utils.go b/pkg/controllers/utils.go similarity index 100% rename from controllers/utils.go rename to pkg/controllers/utils.go diff --git a/controllers/utils_test.go b/pkg/controllers/utils_test.go similarity index 100% rename from controllers/utils_test.go rename to pkg/controllers/utils_test.go From 906e4e24194d711a5df969ea469de0f750b027f2 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Wed, 22 Mar 2023 15:50:56 +0100 Subject: [PATCH 14/21] refactor(Dockerfile): update Dockerfile `FROM` Signed-off-by: Elis Lulja --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 360cf6e..7a62ad1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build binary -FROM golang:1.17 as builder +FROM golang:1.20 as builder WORKDIR /workspace # Copy the Go Modules manifests From 3a24ca6624c830ce07a6c6e623d31acbdf7e6146 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Fri, 24 Mar 2023 16:53:41 +0100 Subject: [PATCH 15/21] refactor(ctrl): make more attempts to resolve IPs Signed-off-by: Elis Lulja --- pkg/controllers/namespace.go | 3 ++ pkg/controllers/service.go | 61 ++++++++++++++++++++++++++---------- pkg/controllers/utils.go | 26 +++++++++++++-- utils.go | 12 +++---- 4 files changed, 76 insertions(+), 26 deletions(-) diff --git a/pkg/controllers/namespace.go b/pkg/controllers/namespace.go index 4d03a25..5046120 100644 --- a/pkg/controllers/namespace.go +++ b/pkg/controllers/namespace.go @@ -172,6 +172,9 @@ func (n *namespaceEventHandler) handleUpdateEvent(namespace *corev1.Namespace, e for _, service := range services.Items { checkedService := checkService(&service, n.ServiceAnnotations) if !checkedService.passed { + if checkedService.err != nil { + n.log.Err(checkedService.err).Msg("cannot check service") + } continue } diff --git a/pkg/controllers/service.go b/pkg/controllers/service.go index 9f33a7f..f504c8a 100644 --- a/pkg/controllers/service.go +++ b/pkg/controllers/service.go @@ -97,16 +97,15 @@ func (s *serviceEventHandler) Create(ce event.CreateEvent, wq workqueue.RateLimi if err != nil { l.Err(err).Msg("cannot check parent namespace") } - return } checkedService := checkService(service, s.ServiceAnnotations) if !checkedService.passed { if checkedService.err != nil { - l.Err(err).Msg("cannot check service") + l.Err(checkedService.err). + Msg("cannot check service") } - return } @@ -141,13 +140,24 @@ func (s *serviceEventHandler) Create(ce event.CreateEvent, wq workqueue.RateLimi func (s *serviceEventHandler) Update(ue event.UpdateEvent, wq workqueue.RateLimitingInterface) { l := s.log.With().Str("name", "update-event-handler").Logger() defer wq.Done(ue.ObjectNew) - curr, currok := ue.ObjectNew.(*corev1.Service) old, oldok := ue.ObjectOld.(*corev1.Service) if !currok || !oldok { + + return + } + + if curr.DeletionTimestamp != nil { + if old.DeletionTimestamp != nil { + return + } + + s.handleDelete(curr) return } + defer wq.Done(ue.ObjectNew) + l = l.With().Str("name", types.NamespacedName{ Namespace: curr.Namespace, Name: curr.Name, @@ -164,14 +174,12 @@ func (s *serviceEventHandler) Update(ue event.UpdateEvent, wq workqueue.RateLimi currChecked := checkService(curr, s.ServiceAnnotations) oldChecked := checkService(old, s.ServiceAnnotations) - if currChecked.err != nil || oldChecked.err != nil { - err := currChecked.err + checkErr := currChecked.err if err != nil { - err = oldChecked.err + checkErr = oldChecked.err } - l.Err(err).Msg("error occurred while getting ips from service") - return + l.Err(checkErr).Msg("error occurred while getting ips from service") } // Easiest cases @@ -199,6 +207,14 @@ func (s *serviceEventHandler) Update(ue event.UpdateEvent, wq workqueue.RateLimi return case !oldChecked.passed && currChecked.passed: l.Info().Msg("sending create...") + + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventCreate, + Object: &serego.Namespace{ + Name: curr.Namespace, + }, + } + s.EventsChan <- &serviceregistry.Event{ EventType: serviceregistry.EventCreate, Object: &serego.Service{ @@ -217,6 +233,21 @@ func (s *serviceEventHandler) Update(ue event.UpdateEvent, wq workqueue.RateLimi return } + // Make sure the namespace and service are created. + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventCreate, + Object: &serego.Namespace{ + Name: curr.Namespace, + }, + } + s.EventsChan <- &serviceregistry.Event{ + EventType: serviceregistry.EventCreate, + Object: &serego.Service{ + Namespace: curr.Namespace, + Name: curr.Name, + }, + } + // Check what is changed oldEndpoints := getEndpointsMapFromSlice(oldChecked.endpoints) currEndpoints := getEndpointsMapFromSlice(currChecked.endpoints) @@ -250,15 +281,11 @@ func (s *serviceEventHandler) Update(ue event.UpdateEvent, wq workqueue.RateLimi // Delete handles delete events. func (s *serviceEventHandler) Delete(de event.DeleteEvent, wq workqueue.RateLimitingInterface) { - l := s.log.With().Str("handler", "service-delete-event-handler").Logger() - defer wq.Done(de.Object) - - service, ok := de.Object.(*corev1.Service) - if !ok { - return - } + wq.Done(de.Object) +} - l = l.With().Str("name", types.NamespacedName{ +func (s *serviceEventHandler) handleDelete(service *corev1.Service) { + l := s.log.With().Str("name", types.NamespacedName{ Namespace: service.Namespace, Name: service.Name, }.String()).Logger() diff --git a/pkg/controllers/utils.go b/pkg/controllers/utils.go index dc7a038..aa387dd 100644 --- a/pkg/controllers/utils.go +++ b/pkg/controllers/utils.go @@ -24,6 +24,7 @@ import ( "fmt" "net" "strings" + "time" serego "github.com/CloudNativeSDWAN/serego/api/core/types" corev1 "k8s.io/api/core/v1" @@ -71,7 +72,7 @@ func filterAnnotations(currentAnnotations map[string]string, filter []string) ma return filtered } -func getIPsFromService(service *corev1.Service) ([]string, error) { +func getIPsFromService(service *corev1.Service, attempts int) ([]string, error) { ipsMap := map[string]bool{} for _, externalIP := range service.Spec.ExternalIPs { ipsMap[externalIP] = true @@ -84,7 +85,11 @@ func getIPsFromService(service *corev1.Service) ([]string, error) { } if ing.Hostname != "" { - resolvedIPs, err := net.LookupHost(ing.Hostname) + if attempts == 0 { + attempts = 1 + } + + resolvedIPs, err := tryResolveHostnames(ing.Hostname, attempts) if err != nil { return nil, err } @@ -102,6 +107,21 @@ func getIPsFromService(service *corev1.Service) ([]string, error) { return ips, nil } +func tryResolveHostnames(hostname string, maxAttempts int) (resolvedIPs []string, err error) { + // TODO: get a context to do this so we know when + // we have to stop checking + for attempts := 0; attempts < maxAttempts; attempts++ { + resolvedIPs, err = net.LookupHost(hostname) + if err == nil { + return resolvedIPs, nil + } + + time.Sleep(2 * time.Second) + } + + return nil, fmt.Errorf("too many failed attempts to resolve hostname: %w", err) +} + func checkNsLabels(labels map[string]string, watchAllByDefault bool) bool { switch labels[watchLabel] { case watchEnabledLabel: @@ -134,7 +154,7 @@ func checkService(service *corev1.Service, annotationsToKeep []string) (result c return } - ips, err := getIPsFromService(service) + ips, err := getIPsFromService(service, 10) if len(ips) == 0 { result.reason = "no valid hostnames/ips found" if err != nil { diff --git a/utils.go b/utils.go index 7e64a33..3757534 100644 --- a/utils.go +++ b/utils.go @@ -96,7 +96,7 @@ func getGSDClient(ctx context.Context) (*sd.RegistrationClient, error) { func getAWSClient(ctx context.Context, region *string) (*servicediscovery.Client, error) { saBytes, err := cluster.GetAWSCredentialsSecret(ctx) if err != nil { - return nil, fmt.Errorf("could not load google service account secret: %s", err) + return nil, fmt.Errorf("could not load aws credentials secret: %s", err) } // TODO: on next versions this will be a const, as it will be moved to @@ -147,19 +147,19 @@ func parseAndResetGSDSettings(gcSettings *types.ServiceDirectorySettings) (*type if gcSettings != nil && gcSettings.DefaultRegion != "" { newSettings.DefaultRegion = gcSettings.DefaultRegion - setupLog.Info("using region defined in settings", "region", gcSettings.DefaultRegion) + // setupLog.Info("using region defined in settings", "region", gcSettings.DefaultRegion) } if gcSettings != nil && gcSettings.ProjectID != "" { newSettings.ProjectID = gcSettings.ProjectID - setupLog.Info("using project ID defined in settings", "project-id", gcSettings.ProjectID) + // setupLog.Info("using project ID defined in settings", "project-id", gcSettings.ProjectID) } if newSettings.DefaultRegion != "" && newSettings.ProjectID != "" { return newSettings, nil } - setupLog.Info("attempting to retrieve some data from Google Cloud...") + // setupLog.Info("attempting to retrieve some data from Google Cloud...") if cluster.WhereAmIRunning() != cluster.GKECluster { return nil, fmt.Errorf("could not load data from Google Cloud: either platform is not GKE or there are no permissions to do so") } @@ -170,7 +170,7 @@ func parseAndResetGSDSettings(gcSettings *types.ServiceDirectorySettings) (*type return nil, fmt.Errorf("could not get region from GCP: %s", err) } newSettings.DefaultRegion = *_defRegion - setupLog.Info("retrieved region from GCP", "region", newSettings.DefaultRegion) + // setupLog.Info("retrieved region from GCP", "region", newSettings.DefaultRegion) } if newSettings.ProjectID == "" { @@ -179,7 +179,7 @@ func parseAndResetGSDSettings(gcSettings *types.ServiceDirectorySettings) (*type return nil, fmt.Errorf("could not get project ID from GCP: %s", err) } newSettings.ProjectID = *_projectID - setupLog.Info("retrieved project ID from GCP", "project ID", newSettings.ProjectID) + // setupLog.Info("retrieved project ID from GCP", "project ID", newSettings.ProjectID) } return newSettings, nil From ce3bcb529ef6e4ee65c880db7f82329990770448 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Fri, 24 Mar 2023 16:55:08 +0100 Subject: [PATCH 16/21] feat(event-handler): use namespace workers Signed-off-by: Elis Lulja --- pkg/serviceregistry/events_handler.go | 29 ++-- pkg/serviceregistry/namespace_worker.go | 194 ++++++++++++++++++++++-- pkg/serviceregistry/utils.go | 9 +- 3 files changed, 205 insertions(+), 27 deletions(-) diff --git a/pkg/serviceregistry/events_handler.go b/pkg/serviceregistry/events_handler.go index 61ba352..45e5173 100644 --- a/pkg/serviceregistry/events_handler.go +++ b/pkg/serviceregistry/events_handler.go @@ -23,6 +23,7 @@ import ( "sync" "time" + serego "github.com/CloudNativeSDWAN/serego/api/core" "github.com/rs/zerolog" ) @@ -44,16 +45,20 @@ type Event struct { } type EventHandler struct { - workers map[string]*namespaceWorkerData - waitGroup sync.WaitGroup - log zerolog.Logger + seregoClient *serego.ServiceRegistry + workers map[string]*namespaceWorkerData + waitGroup sync.WaitGroup + log zerolog.Logger + persistentMeta map[string]string } -func NewEventHandler(log zerolog.Logger) *EventHandler { +func NewEventHandler(seregoClient *serego.ServiceRegistry, persistentMeta map[string]string, log zerolog.Logger) *EventHandler { return &EventHandler{ - workers: map[string]*namespaceWorkerData{}, - waitGroup: sync.WaitGroup{}, - log: log, + seregoClient: seregoClient, + workers: map[string]*namespaceWorkerData{}, + waitGroup: sync.WaitGroup{}, + log: log, + persistentMeta: persistentMeta, } } @@ -92,10 +97,6 @@ func (e *EventHandler) WatchForEvents(mainCtx context.Context, eventsChannel cha continue } - l.Info().Str("namespace", namespaceName). - Msg("received event: retrieving namespace worker in " + - "charge of it...") - nsWorker := e.getOrCreateNamespaceWorker(mainCtx, namespaceName) l.Info().Msg("dispatching event to namespace worker...") @@ -137,8 +138,10 @@ func (e *EventHandler) getOrCreateNamespaceWorker(mainCtx context.Context, name l.Debug().Msg("creating namespace worker...") data := &namespaceWorkerData{ worker: &namespaceWorker{ - log: e.log.With().Str("worker", name+"-event-handler").Logger(), - eventsChan: make(chan *Event, 25), + nsop: e.seregoClient.Namespace(name), + log: e.log.With().Str("worker", name+"-event-handler").Logger(), + eventsChan: make(chan *Event, 25), + persistentMeta: e.persistentMeta, }, } data.ctx, data.canc = context.WithCancel(mainCtx) diff --git a/pkg/serviceregistry/namespace_worker.go b/pkg/serviceregistry/namespace_worker.go index 036aad3..384c9e5 100644 --- a/pkg/serviceregistry/namespace_worker.go +++ b/pkg/serviceregistry/namespace_worker.go @@ -22,7 +22,10 @@ import ( "context" "time" - serego "github.com/CloudNativeSDWAN/serego/api/core/types" + serego "github.com/CloudNativeSDWAN/serego/api/core" + stypes "github.com/CloudNativeSDWAN/serego/api/core/types" + serrors "github.com/CloudNativeSDWAN/serego/api/errors" + "github.com/CloudNativeSDWAN/serego/api/options/register" "github.com/rs/zerolog" ) @@ -34,8 +37,10 @@ type namespaceWorkerData struct { } type namespaceWorker struct { - log zerolog.Logger - eventsChan chan *Event + nsop *serego.NamespaceOperation + log zerolog.Logger + eventsChan chan *Event + persistentMeta map[string]string } func (n *namespaceWorker) handleNamespacedEvents(ctx context.Context) error { @@ -48,17 +53,180 @@ func (n *namespaceWorker) handleNamespacedEvents(ctx context.Context) error { l.Info().Msg("received stop from manager: exiting...") return nil case event := <-n.eventsChan: - switch o := event.Object.(type) { - case *serego.Namespace: - // TODO: handle namespace event - l.Info().Str("event type", string(event.EventType)).Str("name", o.Name).Msg("received namespace event") - case *serego.Service: - // TODO: handle service event - l.Info().Str("event type", string(event.EventType)).Str("name", o.Namespace+"/"+o.Name).Msg("received service event") - case *serego.Endpoint: - // TODO: handle endpoint event - l.Info().Str("event type", string(event.EventType)).Str("name", o.Namespace+"/"+o.Service+"/"+o.Name).Msg("received endpoint event") + + switch event.EventType { + case EventCreate, EventUpdate: + n.handleCreateUpdate(ctx, event) + case EventDelete: + switch obj := event.Object.(type) { + case *stypes.Namespace: + n.handleDeleteNamespace(ctx, obj) + case *stypes.Service: + n.handleDeleteService(ctx, obj) + case *stypes.Endpoint: + n.handleDeleteEndpoint(ctx, obj) + } } } } } + +func (n *namespaceWorker) handleCreateUpdate(mainCtx context.Context, event *Event) { + ctx, canc := context.WithTimeout(mainCtx, time.Minute) + defer canc() + + switch obj := event.Object.(type) { + + case *stypes.Namespace: + l := n.log.With().Logger() + l.Info().Msg("registering namespace...") + if err := n.nsop. + Register(ctx, register.WithMetadata(n.persistentMeta)); err != nil { + l.Err(err).Msg("could not registrer namespace") + } else { + l.Info().Msg("namespace correctly registered") + } + + case *stypes.Service: + l := n.log.With().Str("service-name", obj.Name).Logger() + l.Info().Msg("registering service...") + if err := n.nsop.Service(obj.Name). + Register(ctx, register.WithMetadata(n.persistentMeta)); err != nil { + l.Err(err).Msg("could not registrer service") + } else { + l.Info().Msg("service correctly registered") + } + + case *stypes.Endpoint: + l := n.log.With(). + Str("service-name", obj.Service). + Str("endpoint-name", obj.Name). + Logger() + l.Info().Msg("registering endpoint...") + if err := n.nsop.Service(obj.Service).Endpoint(obj.Name).Register(ctx, + register.WithAddress(obj.Address), + register.WithPort(obj.Port), + register.WithMetadata(obj.Metadata), + register.WithMetadata(n.persistentMeta)); err != nil { + l.Err(err).Msg("could not registrer endpoint") + } else { + l.Info().Msg("endpoint correctly registered") + } + + } +} + +func (n *namespaceWorker) handleDeleteEndpoint(mainCtx context.Context, endpoint *stypes.Endpoint) { + ctx, canc := context.WithTimeout(mainCtx, time.Minute) + defer canc() + + l := n.log.With(). + Str("service", endpoint.Service). + Str("endpoint", endpoint.Name). + Logger() + + eop := n.nsop.Service(endpoint.Service).Endpoint(endpoint.Name) + + ep, err := eop.Get(ctx) + if err != nil { + l.Warn().AnErr("error", err).Msg("cannot check if endpoint exists: it " + + "might be already deleted") + return + } + + if !isOwnedByOperator(ep.Metadata) { + l.Info().Str("reason", "not managed by CNWAN-Operator"). + Msg("skipping endpoint deletion") + return + } + + l.Info().Msg("deleting endpoint...") + err = eop.Deregister(ctx) + if err != nil { + l.Err(err).Msg("cannot delete endpoint") + return + } + + l.Info().Msg("endpoint successfully deleted") +} + +func (n *namespaceWorker) handleDeleteService(mainCtx context.Context, service *stypes.Service) { + ctx, canc := context.WithTimeout(mainCtx, time.Minute) + defer canc() + + l := n.log.With().Str("service", service.Name).Logger() + + sop := n.nsop.Service(service.Name) + + srv, err := sop.Get(ctx) + if err != nil { + l.Warn().AnErr("error", err).Msg("cannot check if service exists: it " + + "might be already deleted") + return + } + + if !isOwnedByOperator(srv.Metadata) { + l.Info().Str("reason", "not managed by CNWAN-Operator"). + Msg("skipping service deletion") + return + } + + _, _, err = sop.Endpoint(serego.Any).List().Next(ctx) + switch { + case err != nil && !serrors.IsIteratorDone(err): + l.Err(err).Msg("cannot check if service is empty") + return + case err == nil: + l.Info().Str("reason", "not empty"). + Msg("skipping service deletion") + return + } + + l.Info().Msg("deleting service...") + err = sop.Deregister(ctx) + if err != nil { + l.Err(err).Msg("cannot delete service") + return + } + + l.Info().Msg("service successfully deleted") +} + +func (n *namespaceWorker) handleDeleteNamespace(mainCtx context.Context, namespace *stypes.Namespace) { + ctx, canc := context.WithTimeout(mainCtx, time.Minute) + defer canc() + + l := n.log.With().Str("namespace", namespace.Name).Logger() + + ns, err := n.nsop.Get(ctx) + if err != nil { + l.Err(err).Msg("cannot check if namespace exists: won't be deleted") + return + } + + if !isOwnedByOperator(ns.Metadata) { + l.Info().Str("reason", "not managed by CNWAN-Operator"). + Msg("skipping service deletion") + return + } + + _, _, err = n.nsop.Service(serego.Any).List().Next(ctx) + switch { + case err != nil && !serrors.IsIteratorDone(err): + l.Err(err).Msg("cannot check if namespace is empty") + return + case err == nil: + l.Info().Str("reason", "not empty"). + Msg("skipping namespace deletion") + return + } + + l.Info().Msg("deleting namespace...") + err = n.nsop.Deregister(ctx) + if err != nil { + l.Err(err).Msg("cannot delete namespace") + return + } + + l.Info().Msg("namespace successfully deleted") +} diff --git a/pkg/serviceregistry/utils.go b/pkg/serviceregistry/utils.go index 34df8fe..c28a8c1 100644 --- a/pkg/serviceregistry/utils.go +++ b/pkg/serviceregistry/utils.go @@ -18,7 +18,9 @@ package serviceregistry -import serego "github.com/CloudNativeSDWAN/serego/api/core/types" +import ( + serego "github.com/CloudNativeSDWAN/serego/api/core/types" +) func getNamespaceNameFromEventObject(event *Event) string { switch parsedObject := event.Object.(type) { @@ -32,3 +34,8 @@ func getNamespaceNameFromEventObject(event *Event) string { return "" } } + +func isOwnedByOperator(metadata map[string]string) bool { + owned, exists := metadata["owner"] + return exists && owned == "cnwan-operator" +} From bb773b3cf0e66c53f1b20f2b35ff1e82c5f7bfa5 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Fri, 24 Mar 2023 16:57:18 +0100 Subject: [PATCH 17/21] refactor(main): use new handlers and controllers Signed-off-by: Elis Lulja --- main.go | 165 +++++++++++++++++++++----------------------------------- 1 file changed, 61 insertions(+), 104 deletions(-) diff --git a/main.go b/main.go index 28d52c3..34c206d 100644 --- a/main.go +++ b/main.go @@ -30,19 +30,11 @@ import ( "github.com/CloudNativeSDWAN/cnwan-operator/pkg/cluster" "github.com/CloudNativeSDWAN/cnwan-operator/pkg/controllers" "github.com/CloudNativeSDWAN/cnwan-operator/pkg/serviceregistry" - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry/aws/cloudmap" - "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry/etcd" - sd "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry/gcloud/servicedirectory" + serego "github.com/CloudNativeSDWAN/serego/api/core" + "github.com/CloudNativeSDWAN/serego/api/options/wrapper" "github.com/rs/zerolog" - clientv3 "go.etcd.io/etcd/client/v3" "gopkg.in/yaml.v3" - corev1 "k8s.io/api/core/v1" - k8sruntime "k8s.io/apimachinery/pkg/runtime" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/log/zap" // +kubebuilder:scaffold:imports ) @@ -71,23 +63,25 @@ const ( CannotRunControllerManager ) -var ( - scheme = k8sruntime.NewScheme() - setupLog = ctrl.Log.WithName("setup") -) +// var ( +// // scheme = k8sruntime.NewScheme() +// setupLog = ctrl.Log.WithName("setup") +// ) -func init() { - _ = clientgoscheme.AddToScheme(scheme) +// func init() { +// _ = clientgoscheme.AddToScheme(scheme) - _ = corev1.AddToScheme(scheme) - // +kubebuilder:scaffold:scheme -} +// _ = corev1.AddToScheme(scheme) +// // +kubebuilder:scaffold:scheme +// } + +var log zerolog.Logger func main() { - ctrl.SetLogger(zap.New(zap.UseDevMode(true))) + log = zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger() if code, err := run(); err != nil { - setupLog.Error(err, "error occurred") + log.Err(err).Msg("error occurred") os.Exit(code) } } @@ -102,7 +96,10 @@ func run() (int, error) { nsName := os.Getenv("CNWAN_OPERATOR_NAMESPACE") if len(nsName) == 0 { - setupLog.Info("CNWAN_OPERATOR_NAMESPACE environment variable does not exist: using default value", "default", defaultNsName) + log.Info(). + Str("default", defaultNsName). + Msg("CNWAN_OPERATOR_NAMESPACE environment variable does not " + + "exist: using default value") nsName = defaultNsName } @@ -116,7 +113,7 @@ func run() (int, error) { if err != nil { return CannotGetConfigmap, fmt.Errorf("unable to retrieve settings from configmap: %w", err) } - setupLog.Info("settings file loaded successfully") + log.Info().Msg("settings file loaded successfully") var _settings *types.Settings if err := yaml.Unmarshal(settingsByte, &_settings); err != nil { @@ -128,25 +125,30 @@ func run() (int, error) { return SettingsValidationError, fmt.Errorf("invalid settings provided: %w", err) } } - setupLog.Info("settings parsed successfully") + log.Info().Msg("settings parsed successfully") - persistentMeta := []sr.MetadataPair{} + persistentMeta := map[string]string{ + "owner": "cnwan-operator", + } if settings.CloudMetadata != nil { // No need to check for network and subnetwork nil as it was already // validate previously. netCfg, err := getNetworkCfg(settings.CloudMetadata.Network, settings.CloudMetadata.SubNetwork) if err != nil { - setupLog.Error(err, "could not get cloud network information, skipping...") + log.Err(err).Msg("could not get cloud network information, skipping...") } else { - setupLog.Info("got network configuration", "cnwan.io/network", netCfg.NetworkName, "cnwan.io/sub-network", netCfg.SubNetworkName) + log.Info(). + Str("cnwan.io/network", netCfg.NetworkName). + Str("cnwan.io/sub-network", netCfg.SubNetworkName). + Msg("got network configuration") if runningIn := cluster.WhereAmIRunning(); runningIn != cluster.UnknownCluster { - persistentMeta = append(persistentMeta, sr.MetadataPair{Key: "cnwan.io/platform", Value: string(runningIn)}) + persistentMeta["cnwan.io/platform"] = string(runningIn) } if netCfg.NetworkName != "" { - persistentMeta = append(persistentMeta, sr.MetadataPair{Key: "cnwan.io/network", Value: netCfg.NetworkName}) + persistentMeta["cnwan.io/network"] = netCfg.NetworkName } if netCfg.NetworkName != "" { - persistentMeta = append(persistentMeta, sr.MetadataPair{Key: "cnwan.io/sub-network", Value: netCfg.SubNetworkName}) + persistentMeta["cnwan.io/sub-network"] = netCfg.SubNetworkName } } } @@ -155,24 +157,28 @@ func run() (int, error) { // Get the service registry //-------------------------------------- - var etcdClient *clientv3.Client - var servreg sr.ServiceRegistry + var seregoClient *serego.ServiceRegistry + + switch { - if settings.ServiceRegistrySettings.EtcdSettings != nil { - setupLog.Info("using etcd as a service registry...") - _cli, err := getEtcdClient(settings.EtcdSettings) + // Etcd + case settings.ServiceRegistrySettings.EtcdSettings != nil: + log.Info().Msg("using etcd") + cli, err := getEtcdClient(settings.EtcdSettings) if err != nil { return CannotEstablishConnectionToEtcd, fmt.Errorf("cannot establish connection to etcd: %w", err) } + defer cli.Close() - etcdClient = _cli - defer etcdClient.Close() - servreg = etcd.NewServiceRegistryWithEtcd(ctx, etcdClient, settings.EtcdSettings.Prefix) - } + seregoClient, err = serego.NewServiceRegistryFromEtcd(cli) + if err != nil { + return CannotEstablishConnectionToEtcd, fmt.Errorf("cannot establish connection to etcd: %w", err) + } - if settings.ServiceRegistrySettings.ServiceDirectorySettings != nil { - setupLog.Info("using gcloud service directory...") - cli, err := getGSDClient(context.Background()) + // Service directory + case settings.ServiceRegistrySettings.ServiceDirectorySettings != nil: + log.Info().Msg("using Service Directory") + cli, err := getGSDClient(ctx) if err != nil { return CannotGetServiceDirectoryClient, fmt.Errorf("cannot get service directory client: %w", err) } @@ -183,39 +189,29 @@ func run() (int, error) { return InvalidServiceDirectorySettings, fmt.Errorf("invalid service directory: %w", err) } - servreg = &sd.Handler{ - ProjectID: sdSettings.ProjectID, - DefaultRegion: sdSettings.DefaultRegion, - Log: setupLog.WithName("ServiceDirectory"), - Context: ctx, - Client: cli, + seregoClient, err = serego.NewServiceRegistryFromServiceDirectory(cli, + wrapper.WithProjectID(sdSettings.ProjectID), + wrapper.WithRegion(sdSettings.DefaultRegion)) + if err != nil { + return CannotGetServiceDirectoryClient, fmt.Errorf("cannot get service directory client: %w", err) } - } - - if settings.ServiceRegistrySettings.CloudMapSettings != nil { - setupLog.Info("using aws cloud map...") + // Cloud Map + case settings.ServiceRegistrySettings.CloudMapSettings != nil: + log.Info().Msg("using Cloud Map") cmSettings, err := parseAndResetAWSCloudMapSettings(settings.CloudMapSettings) if err != nil { return InvalidCloudMapSettings, fmt.Errorf("invalid cloud map settings: %w", err) } - cli, err := getAWSClient(context.Background(), &cmSettings.DefaultRegion) + cli, err := getAWSClient(ctx, &cmSettings.DefaultRegion) if err != nil { return CannotGetCloudMapClient, fmt.Errorf("cannot get cloud map client: %w", err) } - servreg = cloudmap.NewHandler(ctx, cli, setupLog) - } - - srBroker, err := sr.NewBroker(servreg, sr.MetadataPair{Key: opKey, Value: opVal}, persistentMeta...) - if err != nil { - return CannotGetBroker, fmt.Errorf("cannot get service registry broker: %w", err) + seregoClient, _ = serego.NewServiceRegistryFromCloudMap(cli) } - _ = srBroker - - log := zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger() manager, err := controllers.NewManager("") if err != nil { log.Err(err).Msg("cannot create manager") @@ -229,7 +225,7 @@ func run() (int, error) { go func() { defer close(exitChan) eventsChan := make(chan *serviceregistry.Event, 100) - eventHandler := serviceregistry.NewEventHandler(log) + eventHandler := serviceregistry.NewEventHandler(seregoClient, persistentMeta, log) go func() { eventHandler.WatchForEvents(watchCtx, eventsChan) @@ -246,52 +242,13 @@ func run() (int, error) { }, log) manager.Start(ctx) - fmt.Println("closing") + log.Info().Msg("closing") }() <-stopChan watchCanc() <-exitChan - //-------------------------------------- - // Init manager - //-------------------------------------- - - // mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - // Scheme: scheme, - // LeaderElection: false, - // MetricsBindAddress: "0", - // }) - // if err != nil { - // return CannotGetControllerManager, fmt.Errorf("cannot create controller manager: %w", err) - // } - - // if err = (&controllers.ServiceReconciler{ - // Client: mgr.GetClient(), - // Log: ctrl.Log.WithName("controllers").WithName("Service"), - // Scheme: mgr.GetScheme(), - // ServRegBroker: srBroker, - // WatchNamespacesByDefault: settings.WatchNamespacesByDefault, - // AllowedAnnotations: settings.Service.Annotations, - // }).SetupWithManager(mgr); err != nil { - // return CannotCreateServiceController, fmt.Errorf("cannot create service controller: %w", err) - // } - - // if err = (&controllers.NamespaceReconciler{ - // Client: mgr.GetClient(), - // Log: ctrl.Log.WithName("controllers").WithName("Namespace"), - // Scheme: mgr.GetScheme(), - // ServRegBroker: srBroker, - // WatchNamespacesByDefault: settings.WatchNamespacesByDefault, - // AllowedAnnotations: settings.Service.Annotations, - // }).SetupWithManager(mgr); err != nil { - // return CannotCreateNamespaceController, fmt.Errorf("cannot create namespace controller: %w", err) - // } - // // +kubebuilder:scaffold:builder - - // setupLog.Info("starting controller manager...") - // if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { - // return CannotRunControllerManager, fmt.Errorf("cannot run controller manager: %w", err) - // } + log.Info().Msg("goodbye!") return Success, nil } From 53f4f8288ba707003f39b2c9f565db3235af1c97 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Fri, 24 Mar 2023 16:57:42 +0100 Subject: [PATCH 18/21] refactor(Dockerfile): update Dockerfile Signed-off-by: Elis Lulja --- Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7a62ad1..9c34fa6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,6 @@ RUN go mod download # Copy the go source COPY main.go main.go COPY utils.go utils.go -COPY controllers/ controllers/ COPY pkg/ pkg/ COPY internal/ internal/ From 60db1a36048c93a01e7dfcd1ded90230ad0e828f Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Fri, 24 Mar 2023 16:58:10 +0100 Subject: [PATCH 19/21] Update dependencies Signed-off-by: Elis Lulja --- go.mod | 58 ++++++++++--------- go.sum | 175 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 184 insertions(+), 49 deletions(-) diff --git a/go.mod b/go.mod index 1a31234..40b77f8 100644 --- a/go.mod +++ b/go.mod @@ -4,41 +4,42 @@ go 1.20 require ( cloud.google.com/go/compute/metadata v0.2.3 - cloud.google.com/go/servicedirectory v1.8.0 + cloud.google.com/go/servicedirectory v1.9.0 github.com/CloudNativeSDWAN/serego/api v0.1.0 - github.com/aws/aws-sdk-go v1.44.221 - github.com/aws/aws-sdk-go-v2 v1.17.6 - github.com/aws/aws-sdk-go-v2/config v1.18.17 - github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.20.1 + github.com/aws/aws-sdk-go v1.44.229 + github.com/aws/aws-sdk-go-v2 v1.17.7 + github.com/aws/aws-sdk-go-v2/config v1.18.19 + github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.21.0 github.com/go-logr/logr v1.2.3 - github.com/googleapis/gax-go/v2 v2.7.1 + github.com/googleapis/gax-go/v2 v2.8.0 github.com/rs/zerolog v1.29.0 github.com/stretchr/testify v1.8.2 go.etcd.io/etcd/api/v3 v3.5.7 go.etcd.io/etcd/client/v3 v3.5.7 go.uber.org/zap v1.24.0 - google.golang.org/api v0.112.0 - google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 - google.golang.org/grpc v1.53.0 + google.golang.org/api v0.114.0 + google.golang.org/genproto v0.0.0-20230323212658-478b75c54725 + google.golang.org/grpc v1.54.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.26.2 - k8s.io/apimachinery v0.26.2 - k8s.io/client-go v0.26.2 + k8s.io/api v0.26.3 + k8s.io/apimachinery v0.26.3 + k8s.io/client-go v0.26.3 sigs.k8s.io/controller-runtime v0.14.5 ) require ( - cloud.google.com/go/compute v1.18.0 // indirect - cloud.google.com/go/iam v0.12.0 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.17 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.12.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 // indirect + cloud.google.com/go/compute v1.19.0 // indirect + cloud.google.com/go/iam v0.13.0 // indirect + github.com/BurntSushi/toml v0.3.1 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.18 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.12.6 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.18.7 // indirect github.com/aws/smithy-go v1.13.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -55,12 +56,13 @@ require ( github.com/go-openapi/swag v0.19.14 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/googleapis/gax-go v1.0.3 // indirect github.com/imdario/mergo v0.3.6 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -72,6 +74,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect @@ -83,17 +86,22 @@ require ( go.opencensus.io v0.24.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect + golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 // indirect + golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect + golang.org/x/mod v0.8.0 // indirect golang.org/x/net v0.8.0 // indirect golang.org/x/oauth2 v0.6.0 // indirect golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.6.0 // indirect golang.org/x/text v0.8.0 // indirect golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.6.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.28.1 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + honnef.co/go/tools v0.0.1-2020.1.4 // indirect k8s.io/apiextensions-apiserver v0.26.1 // indirect k8s.io/component-base v0.26.1 // indirect k8s.io/klog/v2 v2.80.1 // indirect diff --git a/go.sum b/go.sum index efb2b5e..610b258 100644 --- a/go.sum +++ b/go.sum @@ -13,28 +13,35 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ= +cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicedirectory v1.9.0 h1:SJwk0XX2e26o25ObYUORXx6torSFiYgsGkWSkZgkoSU= +cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 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= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 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/CloudNativeSDWAN/serego/api v0.1.0 h1:pf/mCCOLc68yPkCBvTptb6SRn4g54UWlTGhKWPkZ+mM= @@ -44,47 +51,71 @@ 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/aws/aws-sdk-go v1.44.221/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go-v2 v1.17.6/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2/config v1.18.17/go.mod h1:Lj3E7XcxJnxMa+AYo89YiL68s1cFJRGduChynYU67VA= -github.com/aws/aws-sdk-go-v2/credentials v1.13.17/go.mod h1:K9xeFo1g/YPMguMUD69YpwB4Nyi6W/5wn706xIInJFg= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.0/go.mod h1:neYVaeKr5eT7BzwULuG2YbLhzWZ22lpjKdCybR7AXrQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30/go.mod h1:LUBAO3zNXQjoONBKn/kR1y0Q4cj/D02Ts0uHYjcCQLM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24/go.mod h1:gAuCezX/gob6BSMbItsSlMb6WZGV7K2+fWOvk8xBSto= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31/go.mod h1:5zUjguZfG5qjhG9/wqmuyHRyUftl2B5Cp6NNxNC6kRA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24/go.mod h1:HMA4FZG6fyib+NDo5bpIxX1EhYjrAOveZJY2YR0xrNE= -github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.20.1/go.mod h1:kXRUSok2dElGBpwEsTiKl4BVKao/WUfVGj6XSX/I5ko= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.5/go.mod h1:vuWiaDB30M/QTC+lI3Wj6S/zb7tpUK2MSYgy3Guh2L0= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5/go.mod h1:QjxpHmCwAg0ESGtPQnLIVp7SedTOBMYy+Slr3IfMKeI= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.6/go.mod h1:48WJ9l3dwP0GSHWGc5sFGGlCkuA82Mc2xnw+T6Q8aDw= +github.com/aws/aws-sdk-go v1.44.229 h1:lku0ZSHRzj/qtFVM//QE8VjV6kvJ6CFijDZSsjNaD9A= +github.com/aws/aws-sdk-go v1.44.229/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go-v2 v1.17.7 h1:CLSjnhJSTSogvqUGhIC6LqFKATMRexcxLZ0i/Nzk9Eg= +github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2/config v1.18.19 h1:AqFK6zFNtq4i1EYu+eC7lcKHYnZagMn6SW171la0bGw= +github.com/aws/aws-sdk-go-v2/config v1.18.19/go.mod h1:XvTmGMY8d52ougvakOv1RpiTLPz9dlG/OQHsKU/cMmY= +github.com/aws/aws-sdk-go-v2/credentials v1.13.18 h1:EQMdtHwz0ILTW1hoP+EwuWhwCG1hD6l3+RWFQABET4c= +github.com/aws/aws-sdk-go-v2/credentials v1.13.18/go.mod h1:vnwlwjIe+3XJPBYKu1et30ZPABG3VaXJYr8ryohpIyM= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1 h1:gt57MN3liKiyGopcqgNzJb2+d9MJaKT/q1OksHNXVE4= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1/go.mod h1:lfUx8puBRdM5lVVMQlwt2v+ofiG/X6Ms+dy0UkG/kXw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 h1:sJLYcS+eZn5EeNINGHSCRAwUJMFVqklwkH36Vbyai7M= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 h1:1mnRASEKnkqsntcxHaysxwgVoUUp5dkiB+l3llKnqyg= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32 h1:p5luUImdIqywn6JpQsW3tq5GNOxKmOnEpybzPx+d1lk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32/go.mod h1:XGhIBZDEgfqmFIugclZ6FU7v75nHhBDtzuB4xB/tEi4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25 h1:5LHn8JQ0qvjD9L9JhMtylnkcw7j05GDZqM9Oin6hpr0= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25/go.mod h1:/95IA+0lMnzW6XzqYJRpjjsAbKEORVeO0anQqjd2CNU= +github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.21.0 h1:8Cq/VTVv8EbgDZo3G/0Rk5iUkAzvf+ydvw6ExKscj/w= +github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.21.0/go.mod h1:T9ArVTDM6TUdMyfMGbULOLZMPwEnFhw1qjAoEj0VoHM= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.6 h1:5V7DWLBd7wTELVz5bPpwzYy/sikk0gsgZfj40X+l5OI= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.6/go.mod h1:Y1VOmit/Fn6Tz1uFAeCO6Q7M2fmfXSCLeL5INVYsLuY= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6 h1:B8cauxOH1W1v7rd8RdI/MWnoR4Ze0wIHWrb90qczxj4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6/go.mod h1:Lh/bc9XUf8CfOY6Jp5aIkQtN+j1mc+nExc+KXj9jx2s= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.7 h1:bWNgNdRko2x6gqa0blfATqAZKZokPIeM1vfmQt2pnvM= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.7/go.mod h1:JuTnSoeePXmMVe9G8NcjjwgOKEfZ4cOjMuT2IBT/2eI= +github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +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/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534 h1:rtAn27wIbmOGUs7RIbVgPEjb31ehTVniDwPGXyMxm5U= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/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= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -99,22 +130,30 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-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= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -138,8 +177,11 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -152,8 +194,10 @@ 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.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -166,23 +210,34 @@ 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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/gax-go v1.0.3 h1:9dMLqhaibYONnDRcnHdUs9P8Mw64jLlZTYlDe3leBtQ= +github.com/googleapis/gax-go v1.0.3/go.mod h1:QyXYajJFdARxGzjwUfbDFIse7Spkw81SJ4LrBJXtlQ8= +github.com/googleapis/gax-go/v2 v2.0.2/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= 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/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= +github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= 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/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -197,55 +252,76 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc= +github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 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/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= 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/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -261,25 +337,34 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY= go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA= +go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg= go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY= +go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4= go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 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.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +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= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -289,6 +374,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190221220918-438050ddec5e/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= @@ -297,9 +383,11 @@ golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -310,6 +398,8 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 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-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +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= @@ -319,6 +409,8 @@ 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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.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= @@ -355,6 +447,7 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -363,6 +456,7 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -375,6 +469,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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= 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= @@ -420,10 +515,12 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -433,11 +530,14 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -482,10 +582,13 @@ 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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -503,13 +606,15 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.112.0/go.mod h1:737UfWHNsOq4F3REUTmb+GN9pugkgNLCayLTfoIKpPc= +google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -541,7 +646,9 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230323212658-478b75c54725 h1:VmCWItVXcKboEMCwZaWge+1JLiTCQSngZeINF+wzO+g= +google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -555,7 +662,8 @@ 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.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -568,13 +676,16 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 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= @@ -582,30 +693,46 @@ 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= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU= +k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU= +k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE= +k8s.io/apiextensions-apiserver v0.26.1 h1:cB8h1SRk6e/+i3NOrQgSFij1B2S0Y0wDoNl66bn8RMI= k8s.io/apiextensions-apiserver v0.26.1/go.mod h1:AptjOSXDGuE0JICx/Em15PaoO7buLwTs0dGleIHixSM= -k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= -k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= +k8s.io/apimachinery v0.26.3 h1:dQx6PNETJ7nODU3XPtrwkfuubs6w7sX0M8n61zHIV/k= +k8s.io/apimachinery v0.26.3/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= +k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s= +k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ= +k8s.io/component-base v0.26.1 h1:4ahudpeQXHZL5kko+iDHqLj/FSGAEUnSVO0EBbgDd+4= k8s.io/component-base v0.26.1/go.mod h1:VHrLR0b58oC035w6YQiBSbtsf0ThuSwXP+p5dD/kAWU= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y= k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/controller-runtime v0.14.5 h1:6xaWFqzT5KuAQ9ufgUaj1G/+C4Y1GRkhrxl+BJ9i+5s= sigs.k8s.io/controller-runtime v0.14.5/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= From 633df05d18327e8a34f0a99902116e50f7b83f92 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Fri, 24 Mar 2023 17:12:13 +0100 Subject: [PATCH 20/21] refactor: delete unused code Signed-off-by: Elis Lulja --- pkg/servregistry/aws/cloudmap/doc.go | 21 - pkg/servregistry/aws/cloudmap/endpoint.go | 264 ------ .../aws/cloudmap/endpoint_test.go | 692 -------------- pkg/servregistry/aws/cloudmap/fake_client.go | 119 --- pkg/servregistry/aws/cloudmap/handler.go | 131 --- pkg/servregistry/aws/cloudmap/namespace.go | 226 ----- .../aws/cloudmap/namespace_test.go | 552 ----------- pkg/servregistry/aws/cloudmap/service.go | 267 ------ pkg/servregistry/aws/cloudmap/service_test.go | 790 ---------------- pkg/servregistry/aws/cloudmap/utils.go | 95 -- pkg/servregistry/aws/cloudmap/utils_test.go | 85 -- pkg/servregistry/broker.go | 84 -- pkg/servregistry/broker_test.go | 342 ------- pkg/servregistry/data.go | 54 -- pkg/servregistry/doc.go | 21 - pkg/servregistry/endpoint.go | 151 --- pkg/servregistry/endpoint_test.go | 218 ----- pkg/servregistry/errors.go | 70 -- pkg/servregistry/etcd/doc.go | 103 --- pkg/servregistry/etcd/endpoint.go | 118 --- pkg/servregistry/etcd/endpoint_test.go | 534 ----------- pkg/servregistry/etcd/errors.go | 32 - pkg/servregistry/etcd/example_key_test.go | 149 --- pkg/servregistry/etcd/example_test.go | 125 --- pkg/servregistry/etcd/fake_kv.go | 81 -- pkg/servregistry/etcd/key.go | 342 ------- pkg/servregistry/etcd/key_test.go | 366 -------- pkg/servregistry/etcd/namespace.go | 111 --- pkg/servregistry/etcd/namespace_test.go | 391 -------- pkg/servregistry/etcd/service.go | 105 --- pkg/servregistry/etcd/service_registry.go | 333 ------- .../etcd/service_registry_test.go | 860 ------------------ pkg/servregistry/etcd/service_test.go | 489 ---------- pkg/servregistry/etcd/utils.go | 38 - pkg/servregistry/etcd/utils_test.go | 62 -- .../gcloud/servicedirectory/doc.go | 23 - .../gcloud/servicedirectory/endpoint.go | 210 ----- .../gcloud/servicedirectory/endpoint_test.go | 191 ---- .../servicedirectory/fake_reg_client_test.go | 287 ------ .../gcloud/servicedirectory/namespace.go | 195 ---- .../gcloud/servicedirectory/namespace_test.go | 183 ---- .../registration_client_interface.go | 50 - .../gcloud/servicedirectory/service.go | 203 ----- .../service_directory_handler.go | 117 --- .../service_directory_handler_test.go | 110 --- .../gcloud/servicedirectory/service_test.go | 190 ---- .../gcloud/servicedirectory/utils.go | 93 -- .../gcloud/servicedirectory/utils_test.go | 100 -- pkg/servregistry/namespace.go | 193 ---- pkg/servregistry/namespace_test.go | 311 ------- pkg/servregistry/service.go | 207 ----- pkg/servregistry/service_registry.go | 62 -- pkg/servregistry/service_test.go | 338 ------- pkg/servregistry/utils.go | 49 - 54 files changed, 11533 deletions(-) delete mode 100644 pkg/servregistry/aws/cloudmap/doc.go delete mode 100644 pkg/servregistry/aws/cloudmap/endpoint.go delete mode 100644 pkg/servregistry/aws/cloudmap/endpoint_test.go delete mode 100644 pkg/servregistry/aws/cloudmap/fake_client.go delete mode 100644 pkg/servregistry/aws/cloudmap/handler.go delete mode 100644 pkg/servregistry/aws/cloudmap/namespace.go delete mode 100644 pkg/servregistry/aws/cloudmap/namespace_test.go delete mode 100644 pkg/servregistry/aws/cloudmap/service.go delete mode 100644 pkg/servregistry/aws/cloudmap/service_test.go delete mode 100644 pkg/servregistry/aws/cloudmap/utils.go delete mode 100644 pkg/servregistry/aws/cloudmap/utils_test.go delete mode 100644 pkg/servregistry/broker.go delete mode 100644 pkg/servregistry/broker_test.go delete mode 100644 pkg/servregistry/data.go delete mode 100644 pkg/servregistry/doc.go delete mode 100644 pkg/servregistry/endpoint.go delete mode 100644 pkg/servregistry/endpoint_test.go delete mode 100644 pkg/servregistry/errors.go delete mode 100644 pkg/servregistry/etcd/doc.go delete mode 100644 pkg/servregistry/etcd/endpoint.go delete mode 100644 pkg/servregistry/etcd/endpoint_test.go delete mode 100644 pkg/servregistry/etcd/errors.go delete mode 100644 pkg/servregistry/etcd/example_key_test.go delete mode 100644 pkg/servregistry/etcd/example_test.go delete mode 100644 pkg/servregistry/etcd/fake_kv.go delete mode 100644 pkg/servregistry/etcd/key.go delete mode 100644 pkg/servregistry/etcd/key_test.go delete mode 100644 pkg/servregistry/etcd/namespace.go delete mode 100644 pkg/servregistry/etcd/namespace_test.go delete mode 100644 pkg/servregistry/etcd/service.go delete mode 100644 pkg/servregistry/etcd/service_registry.go delete mode 100644 pkg/servregistry/etcd/service_registry_test.go delete mode 100644 pkg/servregistry/etcd/service_test.go delete mode 100644 pkg/servregistry/etcd/utils.go delete mode 100644 pkg/servregistry/etcd/utils_test.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/doc.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/endpoint.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/endpoint_test.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/fake_reg_client_test.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/namespace.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/namespace_test.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/registration_client_interface.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/service.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/service_directory_handler.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/service_directory_handler_test.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/service_test.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/utils.go delete mode 100644 pkg/servregistry/gcloud/servicedirectory/utils_test.go delete mode 100644 pkg/servregistry/namespace.go delete mode 100644 pkg/servregistry/namespace_test.go delete mode 100644 pkg/servregistry/service.go delete mode 100644 pkg/servregistry/service_registry.go delete mode 100644 pkg/servregistry/service_test.go delete mode 100644 pkg/servregistry/utils.go diff --git a/pkg/servregistry/aws/cloudmap/doc.go b/pkg/servregistry/aws/cloudmap/doc.go deleted file mode 100644 index 432a786..0000000 --- a/pkg/servregistry/aws/cloudmap/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -// Package cloudmap contains code that connects to AWS Cloud Map and manages -// namespaces, services and instances (endpoints) inside it. -package cloudmap diff --git a/pkg/servregistry/aws/cloudmap/endpoint.go b/pkg/servregistry/aws/cloudmap/endpoint.go deleted file mode 100644 index 28fc56a..0000000 --- a/pkg/servregistry/aws/cloudmap/endpoint.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package cloudmap - -import ( - "context" - "errors" - "fmt" - "strconv" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery/types" -) - -func (h *Handler) listOrGetEndpoint(nsName, servName string, epName *string) ([]*sr.Endpoint, error) { - ctx, canc := context.WithTimeout(h.mainCtx, defaultTimeout) - defer canc() - - instList, err := h.Client.DiscoverInstances(ctx, &servicediscovery.DiscoverInstancesInput{ - NamespaceName: aws.String(nsName), - ServiceName: aws.String(servName), - }) - if err != nil { - var oe *types.NamespaceNotFound - if errors.As(err, &oe) { - return nil, sr.ErrNotFound - } - - var os *types.ServiceNotFound - if errors.As(err, &os) { - return nil, sr.ErrNotFound - } - return nil, err - } - - endpList := []*sr.Endpoint{} - for _, inst := range instList.Instances { - if epName != nil && aws.ToString(inst.InstanceId) != *epName { - continue - } - - metadata := inst.Attributes - ipv4 := metadata["AWS_INSTANCE_IPV4"] - if ipv4 == "" { - h.log.WithName("ListEndpoints").Info("skipping instance with no address", "name", inst.InstanceId) - continue - } - - strPort := inst.Attributes["AWS_INSTANCE_PORT"] - if strPort == "" { - h.log.WithName("ListEndpoints").Info("skipping instance with no port", "name", inst.InstanceId) - continue - } - port, _ := strconv.ParseInt(strPort, 10, 32) - - delete(metadata, "AWS_INSTANCE_PORT") - delete(metadata, "AWS_INSTANCE_IPV4") - - ep := &sr.Endpoint{ - NsName: nsName, - ServName: servName, - Name: aws.ToString(inst.InstanceId), - Address: ipv4, - Port: int32(port), - Metadata: metadata, - } - - if epName != nil { - return []*sr.Endpoint{ep}, nil - } - - endpList = append(endpList, ep) - } - - return endpList, nil -} - -// GetEndp returns the endpoint if exists. -func (h *Handler) GetEndp(nsName, servName, endpName string) (*sr.Endpoint, error) { - if nsName == "" { - return nil, sr.ErrNsNameNotProvided - } - if servName == "" { - return nil, sr.ErrServNameNotProvided - } - - list, err := h.listOrGetEndpoint(nsName, servName, &endpName) - if err != nil { - - return nil, err - } - if len(list) == 0 { - return nil, sr.ErrNotFound - } - - return list[0], nil -} - -// ListServ returns a list of services inside the provided namespace. -func (h *Handler) ListEndp(nsName, servName string) (endpList []*sr.Endpoint, err error) { - if nsName == "" { - return nil, sr.ErrNsNameNotProvided - } - if servName == "" { - return nil, sr.ErrServNameNotProvided - } - - return h.listOrGetEndpoint(nsName, servName, nil) -} - -// CreateEndp creates the endpoint. -func (h *Handler) CreateEndp(endp *sr.Endpoint) (*sr.Endpoint, error) { - if endp == nil { - return nil, sr.ErrEndpNotProvided - } - if endp.NsName == "" { - return nil, sr.ErrNsNameNotProvided - } - if endp.ServName == "" { - return nil, sr.ErrServNameNotProvided - } - if endp.Name == "" { - return nil, sr.ErrEndpNameNotProvided - } - if endp.Address == "" { - return nil, fmt.Errorf("no address provided") - } - if endp.Port <= 0 { - return nil, fmt.Errorf("invalid port provided") - } - - _, nsID, err := h.listOrGetNamespace(&endp.NsName) - if err != nil { - return nil, err - } - if len(nsID) == 0 { - return nil, sr.ErrNotFound - } - - _, servID, err := h.listOrGetService(endp.NsName, &endp.ServName) - if err != nil { - return nil, err - } - if len(servID) == 0 { - return nil, sr.ErrNotFound - } - - attributes := endp.Metadata - attributes["AWS_INSTANCE_PORT"] = fmt.Sprintf("%d", endp.Port) - attributes["AWS_INSTANCE_IPV4"] = endp.Address - - ctx, canc := context.WithTimeout(h.mainCtx, defaultTimeout) - defer canc() - out, err := h.Client.RegisterInstance(ctx, &servicediscovery.RegisterInstanceInput{ - ServiceId: aws.String(servID[0].id), - InstanceId: aws.String(endp.Name), - Attributes: attributes, - }) - if err != nil { - var oe *types.ServiceNotFound - if errors.As(err, &oe) { - return nil, sr.ErrNotFound - } - - // any other error - return nil, err - } - - l := h.log.WithName("CreateInstance") - - l.Info("waiting for operation to complete...") - if err := h.pollOperationStatus(aws.ToString(out.OperationId)); err != nil { - l.Info("operation completed with error") - return nil, err - } - l.Info("operation completed successfully") - - return endp, nil -} - -// UpdateEndp updates the endpoint. -func (h *Handler) UpdateEndp(endp *sr.Endpoint) (*sr.Endpoint, error) { - return h.CreateEndp(endp) -} - -// DeleteEndp deletes the endpoint. -func (h *Handler) DeleteEndp(nsName, servName, endpName string) error { - if nsName == "" { - return sr.ErrNsNameNotProvided - } - if servName == "" { - return sr.ErrServNameNotProvided - } - if endpName == "" { - return sr.ErrEndpNameNotProvided - } - - _, nsID, err := h.listOrGetNamespace(&nsName) - if err != nil { - return err - } - if len(nsID) == 0 { - return sr.ErrNotFound - } - - _, servID, err := h.listOrGetService(nsName, &servName) - if err != nil { - return err - } - if len(servID) == 0 { - return sr.ErrNotFound - } - - ctx, canc := context.WithTimeout(h.mainCtx, defaultTimeout) - defer canc() - - out, err := h.Client.DeregisterInstance(ctx, &servicediscovery.DeregisterInstanceInput{ - ServiceId: aws.String(servID[0].id), - InstanceId: aws.String(endpName), - }) - if err != nil { - var oe *types.ServiceNotFound - if errors.As(err, &oe) { - return sr.ErrNotFound - } - - var oi *types.InstanceNotFound - if errors.As(err, &oi) { - return sr.ErrNotFound - } - - // any other error - return err - } - - l := h.log.WithName("DeleteInstance") - - l.Info("waiting for operation to complete...") - if err := h.pollOperationStatus(aws.ToString(out.OperationId)); err != nil { - l.Info("operation completed with error") - return err - } - l.Info("operation completed successfully") - - return nil -} diff --git a/pkg/servregistry/aws/cloudmap/endpoint_test.go b/pkg/servregistry/aws/cloudmap/endpoint_test.go deleted file mode 100644 index 304671b..0000000 --- a/pkg/servregistry/aws/cloudmap/endpoint_test.go +++ /dev/null @@ -1,692 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package cloudmap - -import ( - "context" - "fmt" - "strconv" - "testing" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery/types" - "github.com/stretchr/testify/assert" - ctrl "sigs.k8s.io/controller-runtime" -) - -func TestListOrGetEndpoint(t *testing.T) { - // prepare the testing environment - discoverInstances := func(ctx context.Context, params *servicediscovery.DiscoverInstancesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DiscoverInstancesOutput, error) { - if aws.ToString(params.NamespaceName) == "ns-0" { - return nil, &types.NamespaceNotFound{} - } - - if aws.ToString(params.ServiceName) == "serv-0" { - return nil, &types.ServiceNotFound{} - } - - if aws.ToString(params.ServiceName) == "serv-1" { - return nil, fmt.Errorf("whatever-error") - } - - if aws.ToString(params.ServiceName) == "serv-2" { - return &servicediscovery.DiscoverInstancesOutput{Instances: []types.HttpInstanceSummary{ - { - Attributes: map[string]string{}, - InstanceId: aws.String("endp-1"), - NamespaceName: aws.String("ns-1"), - ServiceName: aws.String("serv-2"), - }, - { - Attributes: map[string]string{"AWS_INSTANCE_IPV4": "10.10.10.10"}, - InstanceId: aws.String("endp-2"), - NamespaceName: aws.String("ns-1"), - ServiceName: aws.String("serv-2"), - }, - { - Attributes: map[string]string{"AWS_INSTANCE_IPV4": "10.10.10.10", "AWS_INSTANCE_PORT": "8080", "key": "value"}, - InstanceId: aws.String("endp-3"), - NamespaceName: aws.String("ns-1"), - ServiceName: aws.String("serv-2"), - }, - { - Attributes: map[string]string{"AWS_INSTANCE_IPV4": "11.11.11.11", "AWS_INSTANCE_PORT": "8080", "key": "value"}, - InstanceId: aws.String("endp-4"), - NamespaceName: aws.String("ns-1"), - ServiceName: aws.String("serv-2"), - }, - }}, nil - } - - return &servicediscovery.DiscoverInstancesOutput{Instances: []types.HttpInstanceSummary{}}, nil - } - - a := assert.New(t) - cases := []struct { - nsName string - servName string - epName *string - cli cloudMapClientIface - expRes []*sr.Endpoint - expErr error - }{ - { - nsName: "ns-0", - servName: "serv-0", - cli: &fakeCloudMapClient{ - _DiscoverInstances: func(ctx context.Context, params *servicediscovery.DiscoverInstancesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DiscoverInstancesOutput, error) { - // check that it really did receive expected values - if aws.ToString(params.NamespaceName) != "ns-0" || aws.ToString(params.ServiceName) != "serv-0" { - return nil, fmt.Errorf("unexpected-values") - } - - return discoverInstances(ctx, params, optFns...) - }, - }, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-0", - cli: &fakeCloudMapClient{_DiscoverInstances: discoverInstances}, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-1", - cli: &fakeCloudMapClient{_DiscoverInstances: discoverInstances}, - expErr: fmt.Errorf("whatever-error"), - }, - { - nsName: "ns-1", - servName: "serv-2", - cli: &fakeCloudMapClient{_DiscoverInstances: discoverInstances}, - expRes: []*sr.Endpoint{ - {Name: "endp-3", NsName: "ns-1", ServName: "serv-2", Port: 8080, Address: "10.10.10.10", Metadata: map[string]string{"key": "value"}}, - {Name: "endp-4", NsName: "ns-1", ServName: "serv-2", Port: 8080, Address: "11.11.11.11", Metadata: map[string]string{"key": "value"}}, - }, - }, - { - nsName: "ns-1", - servName: "serv-2", - epName: aws.String("endp-5"), - cli: &fakeCloudMapClient{_DiscoverInstances: discoverInstances}, - expRes: []*sr.Endpoint{}, - }, - { - nsName: "ns-1", - servName: "serv-2", - epName: aws.String("endp-3"), - cli: &fakeCloudMapClient{_DiscoverInstances: discoverInstances}, - expRes: []*sr.Endpoint{ - {Name: "endp-3", NsName: "ns-1", ServName: "serv-2", Port: 8080, Address: "10.10.10.10", Metadata: map[string]string{"key": "value"}}, - }, - }, - } - - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - res, err := h.listOrGetEndpoint(c.nsName, c.servName, c.epName) - if !a.Equal(c.expRes, res) || !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestGetEndp(t *testing.T) { - // prepare the testing environment - discoverInstances := func(ctx context.Context, params *servicediscovery.DiscoverInstancesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DiscoverInstancesOutput, error) { - if aws.ToString(params.NamespaceName) == "ns-0" { - return nil, &types.NamespaceNotFound{} - } - - if aws.ToString(params.ServiceName) == "serv-0" { - return nil, &types.ServiceNotFound{} - } - - if aws.ToString(params.ServiceName) == "serv-1" { - return nil, fmt.Errorf("whatever-error") - } - - if aws.ToString(params.ServiceName) == "serv-2" { - return &servicediscovery.DiscoverInstancesOutput{Instances: []types.HttpInstanceSummary{ - { - Attributes: map[string]string{}, - InstanceId: aws.String("endp-1"), - NamespaceName: aws.String("ns-1"), - ServiceName: aws.String("serv-2"), - }, - { - Attributes: map[string]string{"AWS_INSTANCE_IPV4": "10.10.10.10"}, - InstanceId: aws.String("endp-2"), - NamespaceName: aws.String("ns-1"), - ServiceName: aws.String("serv-2"), - }, - { - Attributes: map[string]string{"AWS_INSTANCE_IPV4": "10.10.10.10", "AWS_INSTANCE_PORT": "8080", "key": "value"}, - InstanceId: aws.String("endp-3"), - NamespaceName: aws.String("ns-1"), - ServiceName: aws.String("serv-2"), - }, - { - Attributes: map[string]string{"AWS_INSTANCE_IPV4": "11.11.11.11", "AWS_INSTANCE_PORT": "8080", "key": "value"}, - InstanceId: aws.String("endp-4"), - NamespaceName: aws.String("ns-1"), - ServiceName: aws.String("serv-2"), - }, - }}, nil - } - - return &servicediscovery.DiscoverInstancesOutput{Instances: []types.HttpInstanceSummary{}}, nil - } - - a := assert.New(t) - cases := []struct { - nsName string - servName string - endpName string - cli cloudMapClientIface - expRes *sr.Endpoint - expErr error - }{ - { - expErr: sr.ErrNsNameNotProvided, - }, - { - nsName: "ns-0", - expErr: sr.ErrServNameNotProvided, - }, - { - nsName: "ns-0", - servName: "serv-0", - cli: &fakeCloudMapClient{ - _DiscoverInstances: func(ctx context.Context, params *servicediscovery.DiscoverInstancesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DiscoverInstancesOutput, error) { - // check that it really did receive expected values - if aws.ToString(params.NamespaceName) != "ns-0" || aws.ToString(params.ServiceName) != "serv-0" { - return nil, fmt.Errorf("unexpected-values") - } - - return discoverInstances(ctx, params, optFns...) - }, - }, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-0", - cli: &fakeCloudMapClient{_DiscoverInstances: discoverInstances}, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-2", - endpName: "endp-5", - cli: &fakeCloudMapClient{_DiscoverInstances: discoverInstances}, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-2", - endpName: "endp-3", - cli: &fakeCloudMapClient{_DiscoverInstances: discoverInstances}, - expRes: &sr.Endpoint{Name: "endp-3", NsName: "ns-1", ServName: "serv-2", Port: 8080, Address: "10.10.10.10", Metadata: map[string]string{"key": "value"}}, - }, - } - - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - res, err := h.GetEndp(c.nsName, c.servName, c.endpName) - if !a.Equal(c.expRes, res) || !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestListEndp(t *testing.T) { - // prepare the testing environment - discoverInstances := func(ctx context.Context, params *servicediscovery.DiscoverInstancesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DiscoverInstancesOutput, error) { - if aws.ToString(params.NamespaceName) == "ns-0" { - return nil, &types.NamespaceNotFound{} - } - - if aws.ToString(params.ServiceName) == "serv-0" { - return nil, &types.ServiceNotFound{} - } - - if aws.ToString(params.ServiceName) == "serv-1" { - return nil, fmt.Errorf("whatever-error") - } - - if aws.ToString(params.ServiceName) == "serv-2" { - return &servicediscovery.DiscoverInstancesOutput{Instances: []types.HttpInstanceSummary{ - { - Attributes: map[string]string{}, - InstanceId: aws.String("endp-1"), - NamespaceName: aws.String("ns-1"), - ServiceName: aws.String("serv-2"), - }, - { - Attributes: map[string]string{"AWS_INSTANCE_IPV4": "10.10.10.10"}, - InstanceId: aws.String("endp-2"), - NamespaceName: aws.String("ns-1"), - ServiceName: aws.String("serv-2"), - }, - { - Attributes: map[string]string{"AWS_INSTANCE_IPV4": "10.10.10.10", "AWS_INSTANCE_PORT": "8080", "key": "value"}, - InstanceId: aws.String("endp-3"), - NamespaceName: aws.String("ns-1"), - ServiceName: aws.String("serv-2"), - }, - { - Attributes: map[string]string{"AWS_INSTANCE_IPV4": "11.11.11.11", "AWS_INSTANCE_PORT": "8080", "key": "value"}, - InstanceId: aws.String("endp-4"), - NamespaceName: aws.String("ns-1"), - ServiceName: aws.String("serv-2"), - }, - }}, nil - } - - return &servicediscovery.DiscoverInstancesOutput{Instances: []types.HttpInstanceSummary{}}, nil - } - - a := assert.New(t) - cases := []struct { - nsName string - servName string - cli cloudMapClientIface - expRes []*sr.Endpoint - expErr error - }{ - { - expErr: sr.ErrNsNameNotProvided, - }, - { - nsName: "ns-0", - expErr: sr.ErrServNameNotProvided, - }, - { - nsName: "ns-0", - servName: "serv-0", - cli: &fakeCloudMapClient{ - _DiscoverInstances: func(ctx context.Context, params *servicediscovery.DiscoverInstancesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DiscoverInstancesOutput, error) { - // check that it really did receive expected values - if aws.ToString(params.NamespaceName) != "ns-0" || aws.ToString(params.ServiceName) != "serv-0" { - return nil, fmt.Errorf("unexpected-values") - } - - return discoverInstances(ctx, params, optFns...) - }, - }, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-0", - cli: &fakeCloudMapClient{_DiscoverInstances: discoverInstances}, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-1", - cli: &fakeCloudMapClient{_DiscoverInstances: discoverInstances}, - expErr: fmt.Errorf("whatever-error"), - }, - } - - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - res, err := h.ListEndp(c.nsName, c.servName) - if !a.Equal(c.expRes, res) || !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestCreateEndp(t *testing.T) { - // prepare the testing environment - listNamespaces := func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("ns-arn-1"), Id: aws.String("ns-id-1"), Name: aws.String("ns-1")}, - {Arn: aws.String("ns-arn-2"), Id: aws.String("ns-id-2"), Name: aws.String("ns-2")}, - {Arn: aws.String("ns-arn-3"), Id: aws.String("ns-id-3"), Name: aws.String("ns-3")}, - }}, nil - } - listServices := func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - switch params.Filters[0].Values[0] { - case "ns-id-1": - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-1"), Id: aws.String("serv-id-1"), Name: aws.String("serv-1")}, - {Arn: aws.String("serv-arn-2"), Id: aws.String("serv-id-2"), Name: aws.String("serv-2")}, - }}, nil - case "ns-id-2": - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-3"), Id: aws.String("serv-id-3"), Name: aws.String("serv-3")}, - }}, nil - default: - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{}}, nil - } - } - listTagsForResource := func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - switch aws.ToString(params.ResourceARN) { - case "ns-arn-1", "ns-arn-2", "ns-arn-3", "serv-arn-1", "serv-arn-2", "serv-arn-3": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key"), Value: aws.String("value")}}}, nil - default: - return nil, fmt.Errorf("whatever-error") - } - } - - endp := &sr.Endpoint{NsName: "ns-1", ServName: "serv-1", Name: "endp-1", Address: "10.10.10.10", Port: 80, Metadata: map[string]string{"key": "val"}} - a := assert.New(t) - cases := []struct { - endp *sr.Endpoint - cli cloudMapClientIface - expRes *sr.Endpoint - expErr error - }{ - { - expErr: sr.ErrEndpNotProvided, - }, - { - endp: &sr.Endpoint{}, - expErr: sr.ErrNsNameNotProvided, - }, - { - endp: &sr.Endpoint{NsName: "ns-1"}, - expErr: sr.ErrServNameNotProvided, - }, - { - endp: &sr.Endpoint{NsName: "ns-1", ServName: "serv-1"}, - expErr: sr.ErrEndpNameNotProvided, - }, - { - endp: &sr.Endpoint{NsName: "ns-1", ServName: "serv-1", Name: "endp-1"}, - expErr: fmt.Errorf("no address provided"), - }, - { - endp: &sr.Endpoint{NsName: "ns-1", ServName: "serv-1", Name: "endp-1", Address: "10.10.10.10"}, - expErr: fmt.Errorf("invalid port provided"), - }, - { - endp: endp, - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - endp: &sr.Endpoint{NsName: "ns-4", ServName: "serv-1", Name: "endp-1", Address: "10.10.10.10", Port: 80}, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices}, - expErr: sr.ErrNotFound, - }, - { - endp: endp, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, - _ListServices: func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }}, - expErr: fmt.Errorf("whatever-error"), - }, - { - endp: &sr.Endpoint{NsName: "ns-1", ServName: "serv-4", Name: "endp-1", Address: "10.10.10.10", Port: 80}, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices}, - expErr: sr.ErrNotFound, - }, - { - endp: endp, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices, - _RegisterInstance: func(ctx context.Context, params *servicediscovery.RegisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.RegisterInstanceOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - endp: endp, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices, - _RegisterInstance: func(ctx context.Context, params *servicediscovery.RegisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.RegisterInstanceOutput, error) { - return nil, &types.ServiceNotFound{} - }, - }, - expErr: sr.ErrNotFound, - }, - { - endp: endp, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices, - _RegisterInstance: func(ctx context.Context, params *servicediscovery.RegisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.RegisterInstanceOutput, error) { - if aws.ToString(params.InstanceId) != endp.Name { - return nil, fmt.Errorf("provided endpoint name is not correct") - } - if aws.ToString(params.ServiceId) != "serv-id-1" { - return nil, fmt.Errorf("provided service id is not correct") - } - if val := params.Attributes["AWS_INSTANCE_PORT"]; val != strconv.Itoa(int(endp.Port)) { - return nil, fmt.Errorf("provided endpoint port is not correct") - } - if val := params.Attributes["AWS_INSTANCE_IPV4"]; val != "10.10.10.10" { - return nil, fmt.Errorf("provided endpoint address is not correct") - } - if val := params.Attributes["key"]; val != "val" { - return nil, fmt.Errorf("provided endpoint metadata is not correct") - } - - return &servicediscovery.RegisterInstanceOutput{OperationId: aws.String("op-id-1")}, nil - }, - _GetOperation: func(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) { - return &servicediscovery.GetOperationOutput{Operation: &types.Operation{Status: types.OperationStatusSuccess}}, nil - }, - }, - expRes: endp, - }, - { - endp: endp, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices, - _RegisterInstance: func(ctx context.Context, params *servicediscovery.RegisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.RegisterInstanceOutput, error) { - return &servicediscovery.RegisterInstanceOutput{OperationId: aws.String("op-id-1")}, nil - }, - _GetOperation: func(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) { - return &servicediscovery.GetOperationOutput{Operation: &types.Operation{Status: types.OperationStatusFail, ErrorMessage: aws.String("whatever-error")}}, nil - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - } - - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - res, err := h.CreateEndp(c.endp) - if !a.Equal(c.expRes, res) || !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestDeleteEndp(t *testing.T) { - // prepare the testing environment - listNamespaces := func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("ns-arn-1"), Id: aws.String("ns-id-1"), Name: aws.String("ns-1")}, - {Arn: aws.String("ns-arn-2"), Id: aws.String("ns-id-2"), Name: aws.String("ns-2")}, - {Arn: aws.String("ns-arn-3"), Id: aws.String("ns-id-3"), Name: aws.String("ns-3")}, - }}, nil - } - listServices := func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - switch params.Filters[0].Values[0] { - case "ns-id-1": - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-1"), Id: aws.String("serv-id-1"), Name: aws.String("serv-1")}, - {Arn: aws.String("serv-arn-2"), Id: aws.String("serv-id-2"), Name: aws.String("serv-2")}, - }}, nil - case "ns-id-2": - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-3"), Id: aws.String("serv-id-3"), Name: aws.String("serv-3")}, - }}, nil - default: - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{}}, nil - } - } - listTagsForResource := func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - switch aws.ToString(params.ResourceARN) { - case "ns-arn-1", "ns-arn-2", "ns-arn-3", "serv-arn-1", "serv-arn-2", "serv-arn-3": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key"), Value: aws.String("value")}}}, nil - default: - return nil, fmt.Errorf("whatever-error") - } - } - - endp := &sr.Endpoint{NsName: "ns-1", ServName: "serv-1", Name: "endp-1", Address: "10.10.10.10", Port: 80, Metadata: map[string]string{"key": "val"}} - a := assert.New(t) - cases := []struct { - nsName string - servName string - endpName string - cli cloudMapClientIface - expErr error - }{ - { - expErr: sr.ErrNsNameNotProvided, - }, - { - nsName: "ns-1", - expErr: sr.ErrServNameNotProvided, - }, - { - nsName: "ns-1", - servName: "serv-1", - expErr: sr.ErrEndpNameNotProvided, - }, - { - nsName: "ns-1", - servName: "serv-1", - endpName: "endp-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - nsName: "ns-4", - servName: "serv-1", - endpName: "endp-1", - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices}, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-1", - endpName: "endp-1", - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, - _ListServices: func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }}, - expErr: fmt.Errorf("whatever-error"), - }, - { - nsName: "ns-1", - servName: "serv-5", - endpName: "endp-1", - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices}, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-1", - endpName: "endp-1", - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices, - _DeregisterInstance: func(ctx context.Context, params *servicediscovery.DeregisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeregisterInstanceOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - nsName: "ns-1", - servName: "serv-1", - endpName: "endp-1", - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices, - _DeregisterInstance: func(ctx context.Context, params *servicediscovery.DeregisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeregisterInstanceOutput, error) { - return nil, &types.ServiceNotFound{} - }, - }, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-1", - endpName: "endp-1", - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices, - _DeregisterInstance: func(ctx context.Context, params *servicediscovery.DeregisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeregisterInstanceOutput, error) { - return nil, &types.InstanceNotFound{} - }, - }, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-1", - endpName: "endp-1", - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices, - _DeregisterInstance: func(ctx context.Context, params *servicediscovery.DeregisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeregisterInstanceOutput, error) { - if aws.ToString(params.InstanceId) != endp.Name { - return nil, fmt.Errorf("provided endpoint name is not correct") - } - if aws.ToString(params.ServiceId) != "serv-id-1" { - return nil, fmt.Errorf("provided service id is not correct") - } - - return &servicediscovery.DeregisterInstanceOutput{OperationId: aws.String("op-id-1")}, nil - }, - _GetOperation: func(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) { - return &servicediscovery.GetOperationOutput{Operation: &types.Operation{Status: types.OperationStatusSuccess}}, nil - }, - }, - }, - { - nsName: "ns-1", - servName: "serv-1", - endpName: "endp-1", - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices, - _DeregisterInstance: func(ctx context.Context, params *servicediscovery.DeregisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeregisterInstanceOutput, error) { - return &servicediscovery.DeregisterInstanceOutput{OperationId: aws.String("op-id-1")}, nil - }, - _GetOperation: func(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) { - return &servicediscovery.GetOperationOutput{Operation: &types.Operation{Status: types.OperationStatusFail, ErrorMessage: aws.String("whatever-error")}}, nil - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - } - - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - if !a.Equal(c.expErr, h.DeleteEndp(c.nsName, c.servName, c.endpName)) { - a.FailNow("case failed", "case", i) - } - } -} diff --git a/pkg/servregistry/aws/cloudmap/fake_client.go b/pkg/servregistry/aws/cloudmap/fake_client.go deleted file mode 100644 index 7a8b3cc..0000000 --- a/pkg/servregistry/aws/cloudmap/fake_client.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package cloudmap - -import ( - "context" - - "github.com/aws/aws-sdk-go-v2/service/servicediscovery" -) - -type cloudMapClientIface interface { - CreateHttpNamespace(ctx context.Context, params *servicediscovery.CreateHttpNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreateHttpNamespaceOutput, error) - CreatePrivateDnsNamespace(ctx context.Context, params *servicediscovery.CreatePrivateDnsNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreatePrivateDnsNamespaceOutput, error) - CreatePublicDnsNamespace(ctx context.Context, params *servicediscovery.CreatePublicDnsNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreatePublicDnsNamespaceOutput, error) - CreateService(ctx context.Context, params *servicediscovery.CreateServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreateServiceOutput, error) - DeleteNamespace(ctx context.Context, params *servicediscovery.DeleteNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteNamespaceOutput, error) - DeleteService(ctx context.Context, params *servicediscovery.DeleteServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteServiceOutput, error) - DeregisterInstance(ctx context.Context, params *servicediscovery.DeregisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeregisterInstanceOutput, error) - DiscoverInstances(ctx context.Context, params *servicediscovery.DiscoverInstancesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DiscoverInstancesOutput, error) - GetInstance(ctx context.Context, params *servicediscovery.GetInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetInstanceOutput, error) - GetInstancesHealthStatus(ctx context.Context, params *servicediscovery.GetInstancesHealthStatusInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetInstancesHealthStatusOutput, error) - GetNamespace(ctx context.Context, params *servicediscovery.GetNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetNamespaceOutput, error) - GetOperation(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) - GetService(ctx context.Context, params *servicediscovery.GetServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetServiceOutput, error) - ListInstances(ctx context.Context, params *servicediscovery.ListInstancesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListInstancesOutput, error) - ListNamespaces(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) - ListOperations(ctx context.Context, params *servicediscovery.ListOperationsInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListOperationsOutput, error) - ListServices(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) - ListTagsForResource(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) - RegisterInstance(ctx context.Context, params *servicediscovery.RegisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.RegisterInstanceOutput, error) - TagResource(ctx context.Context, params *servicediscovery.TagResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.TagResourceOutput, error) - UntagResource(ctx context.Context, params *servicediscovery.UntagResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.UntagResourceOutput, error) - UpdateHttpNamespace(ctx context.Context, params *servicediscovery.UpdateHttpNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.UpdateHttpNamespaceOutput, error) - UpdateInstanceCustomHealthStatus(ctx context.Context, params *servicediscovery.UpdateInstanceCustomHealthStatusInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.UpdateInstanceCustomHealthStatusOutput, error) - UpdatePrivateDnsNamespace(ctx context.Context, params *servicediscovery.UpdatePrivateDnsNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.UpdatePrivateDnsNamespaceOutput, error) - UpdatePublicDnsNamespace(ctx context.Context, params *servicediscovery.UpdatePublicDnsNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.UpdatePublicDnsNamespaceOutput, error) - UpdateService(ctx context.Context, params *servicediscovery.UpdateServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.UpdateServiceOutput, error) -} - -type fakeCloudMapClient struct { - cloudMapClientIface - - _CreateHttpNamespace func(ctx context.Context, params *servicediscovery.CreateHttpNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreateHttpNamespaceOutput, error) - _GetOperation func(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) - _ListNamespaces func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) - _ListTagsForResource func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) - _TagResource func(ctx context.Context, params *servicediscovery.TagResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.TagResourceOutput, error) - _DeleteNamespace func(ctx context.Context, params *servicediscovery.DeleteNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteNamespaceOutput, error) - _ListServices func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) - _CreateService func(ctx context.Context, params *servicediscovery.CreateServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreateServiceOutput, error) - _DeleteService func(ctx context.Context, params *servicediscovery.DeleteServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteServiceOutput, error) - _DiscoverInstances func(ctx context.Context, params *servicediscovery.DiscoverInstancesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DiscoverInstancesOutput, error) - _RegisterInstance func(ctx context.Context, params *servicediscovery.RegisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.RegisterInstanceOutput, error) - _DeregisterInstance func(ctx context.Context, params *servicediscovery.DeregisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeregisterInstanceOutput, error) -} - -func (f *fakeCloudMapClient) CreateHttpNamespace(ctx context.Context, params *servicediscovery.CreateHttpNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreateHttpNamespaceOutput, error) { - return f._CreateHttpNamespace(ctx, params, optFns...) -} - -func (f *fakeCloudMapClient) GetOperation(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) { - return f._GetOperation(ctx, params, optFns...) -} - -func (f *fakeCloudMapClient) ListNamespaces(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return f._ListNamespaces(ctx, params, optFns...) -} - -func (f *fakeCloudMapClient) ListTagsForResource(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - return f._ListTagsForResource(ctx, params, optFns...) -} - -func (f *fakeCloudMapClient) TagResource(ctx context.Context, params *servicediscovery.TagResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.TagResourceOutput, error) { - return f._TagResource(ctx, params, optFns...) -} - -func (f *fakeCloudMapClient) DeleteNamespace(ctx context.Context, params *servicediscovery.DeleteNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteNamespaceOutput, error) { - return f._DeleteNamespace(ctx, params, optFns...) -} - -func (f *fakeCloudMapClient) ListServices(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - return f._ListServices(ctx, params, optFns...) -} - -func (f *fakeCloudMapClient) CreateService(ctx context.Context, params *servicediscovery.CreateServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreateServiceOutput, error) { - return f._CreateService(ctx, params, optFns...) -} - -func (f *fakeCloudMapClient) DeleteService(ctx context.Context, params *servicediscovery.DeleteServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteServiceOutput, error) { - return f._DeleteService(ctx, params, optFns...) -} - -func (f *fakeCloudMapClient) DiscoverInstances(ctx context.Context, params *servicediscovery.DiscoverInstancesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DiscoverInstancesOutput, error) { - return f._DiscoverInstances(ctx, params, optFns...) -} - -func (f *fakeCloudMapClient) RegisterInstance(ctx context.Context, params *servicediscovery.RegisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.RegisterInstanceOutput, error) { - return f._RegisterInstance(ctx, params, optFns...) -} - -func (f *fakeCloudMapClient) DeregisterInstance(ctx context.Context, params *servicediscovery.DeregisterInstanceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeregisterInstanceOutput, error) { - return f._DeregisterInstance(ctx, params, optFns...) -} diff --git a/pkg/servregistry/aws/cloudmap/handler.go b/pkg/servregistry/aws/cloudmap/handler.go deleted file mode 100644 index 7b748c4..0000000 --- a/pkg/servregistry/aws/cloudmap/handler.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package cloudmap - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "time" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery" - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" -) - -const ( - defaultTimeout time.Duration = time.Minute -) - -var ( - // pollOperationFrequency is the time betwenn two consecutive - // pollOperationResult calls. - pollOperationFrequency time.Duration = 2 * time.Second -) - -// cloudMapIDs is used to hold ARNs and IDs and is only used internally -type cloudMapIDs struct { - arn string - id string -} - -// Handler is in charge of handling all the operations that need to be -// performed in AWS Cloud Map. -type Handler struct { - Client cloudMapClientIface - // TODO: on next versions the context will be provided explicitly for - // each call. - mainCtx context.Context - log logr.Logger -} - -// NewHandler returns a new instance of the Handler. -func NewHandler(ctx context.Context, client *servicediscovery.Client, log logr.Logger) *Handler { - return &Handler{client, ctx, log} -} - -func (h *Handler) ExtractData(ns *corev1.Namespace, serv *corev1.Service) (*sr.Namespace, *sr.Service, []*sr.Endpoint, error) { - // NOTE: on future versions, this function will be removed from service - // registry and moved to the broker instead: it's not this package's job - // to convert structs. - if ns == nil { - return nil, nil, nil, sr.ErrNsNotProvided - } - if serv == nil { - return nil, nil, nil, sr.ErrServNotProvided - } - - // Parse the namespace - namespaceData := &sr.Namespace{ - Name: ns.Name, - Metadata: ns.Annotations, - } - if namespaceData.Metadata == nil { - namespaceData.Metadata = map[string]string{} - } - - // Parse the service - // NOTE: we put metadata on the service in service directory, - // not on the endpoints - serviceData := &sr.Service{ - Name: serv.Name, - NsName: ns.Name, - Metadata: serv.Annotations, - } - if serviceData.Metadata == nil { - serviceData.Metadata = map[string]string{} - } - - // Get the endpoints from the service - // First, build the ips - ips := []string{} - ips = append(ips, serv.Spec.ExternalIPs...) - - // Get data from load balancers - for _, ing := range serv.Status.LoadBalancer.Ingress { - ips = append(ips, ing.IP) - } - - endpointsData := []*sr.Endpoint{} - for _, port := range serv.Spec.Ports { - for _, ip := range ips { - - // Create an hashed name for this - toBeHashed := fmt.Sprintf("%s-%d", ip, port.Port) - h := sha256.New() - h.Write([]byte(toBeHashed)) - hash := hex.EncodeToString(h.Sum(nil)) - - // Only take the first 10 characters of the hashed name - name := fmt.Sprintf("%s-%s", serv.Name, hash[:10]) - endpointsData = append(endpointsData, &sr.Endpoint{ - Name: name, - NsName: namespaceData.Name, - ServName: serviceData.Name, - Address: ip, - Port: port.Port, - Metadata: map[string]string{}, - }) - } - } - - return namespaceData, serviceData, endpointsData, nil -} diff --git a/pkg/servregistry/aws/cloudmap/namespace.go b/pkg/servregistry/aws/cloudmap/namespace.go deleted file mode 100644 index 63b0ba1..0000000 --- a/pkg/servregistry/aws/cloudmap/namespace.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package cloudmap - -import ( - "context" - "errors" - "time" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery/types" -) - -// CreateNs creates the namespace. -func (h *Handler) CreateNs(ns *sr.Namespace) (*sr.Namespace, error) { - if ns == nil { - return nil, sr.ErrNsNotProvided - } - if ns.Name == "" { - return nil, sr.ErrNsNameNotProvided - } - - opID, err := func() (string, error) { - ctx, canc := context.WithTimeout(h.mainCtx, defaultTimeout) - defer canc() - - out, err := h.Client.CreateHttpNamespace(ctx, &servicediscovery.CreateHttpNamespaceInput{ - Name: aws.String(ns.Name), - Tags: fromMapToTagsSlice(ns.Metadata), - }) - - if err == nil { - return aws.ToString(out.OperationId), nil - } - - var oe *types.NamespaceAlreadyExists - if errors.As(err, &oe) { - return "", sr.ErrAlreadyExists - } - - return "", err - }() - if err != nil { - return nil, err - } - - l := h.log.WithName("CreateNamespace") - - l.Info("waiting for operation to complete...") - if err := h.pollOperationStatus(opID); err != nil { - l.Info("operation completed with error") - return nil, err - } - l.Info("operation completed successfully") - - return ns, nil -} - -func (h *Handler) listOrGetNamespace(name *string) ([]*sr.Namespace, []*cloudMapIDs, error) { - ctx, canc := context.WithTimeout(h.mainCtx, defaultTimeout) - out, err := h.Client.ListNamespaces(ctx, &servicediscovery.ListNamespacesInput{}) - if err != nil { - canc() - return nil, nil, err - } - canc() - - list := []*sr.Namespace{} - ids := []*cloudMapIDs{} - for _, ns := range out.Namespaces { - if name != nil && aws.ToString(ns.Name) != *name { - // move on, this is not the namespace you're looking for. - continue - } - arn := aws.ToString(ns.Arn) - id := aws.ToString(ns.Id) - - nsItem := &sr.Namespace{ - Name: aws.ToString(ns.Name), - Metadata: map[string]string{}, - } - - nsItem.Metadata = func() map[string]string { - tagCtx, tagCanc := context.WithTimeout(h.mainCtx, 30*time.Second) - defer tagCanc() - - tags, err := h.Client.ListTagsForResource(tagCtx, &servicediscovery.ListTagsForResourceInput{ - ResourceARN: ns.Arn, - }) - if err != nil { - h.log.WithName("ListTagsForResource").Info("error while getting tags", "error", err, "name", nsItem.Name) - return map[string]string{} - } - - return fromTagsSliceToMap(tags.Tags) - }() - - if name != nil { - // if you're here, it means that you are indeed the namespace we - // are looking for. - return []*sr.Namespace{nsItem}, []*cloudMapIDs{{arn, id}}, nil - } - - list = append(list, nsItem) - ids = append(ids, &cloudMapIDs{arn, id}) - } - - return list, ids, nil -} - -// ListNs returns a list of all namespaces. -func (h *Handler) ListNs() (nsList []*sr.Namespace, err error) { - nsList, _, err = h.listOrGetNamespace(nil) - return -} - -// GetNs returns the namespace if exists. -func (h *Handler) GetNs(name string) (*sr.Namespace, error) { - if name == "" { - return nil, sr.ErrNsNameNotProvided - } - - list, _, err := h.listOrGetNamespace(&name) - if err != nil { - return nil, err - } - - if len(list) == 0 { - return nil, sr.ErrNotFound - } - - return list[0], nil -} - -// GetNs returns the namespace if exists. -func (h *Handler) UpdateNs(ns *sr.Namespace) (*sr.Namespace, error) { - if ns == nil { - return nil, sr.ErrNsNotProvided - } - if ns.Name == "" { - return nil, sr.ErrNsNameNotProvided - } - - _, ids, err := h.listOrGetNamespace(&ns.Name) - if err != nil { - return nil, err - } - - if len(ids) == 0 { - return nil, sr.ErrNotFound - } - - err = h.tagResource(ids[0].arn, fromMapToTagsSlice(ns.Metadata)) - if err == nil { - return ns, nil - } - - var oe *types.ResourceNotFoundException - if errors.As(err, &oe) { - return nil, sr.ErrNotFound - } - - return nil, err -} - -// GetNs returns the namespace if exists. -func (h *Handler) DeleteNs(name string) error { - if name == "" { - return sr.ErrNsNameNotProvided - } - - _, ids, err := h.listOrGetNamespace(&name) - if err != nil { - return err - } - - if len(ids) == 0 { - return sr.ErrNotFound - } - - ctx, canc := context.WithTimeout(h.mainCtx, time.Minute) - defer canc() - - out, err := h.Client.DeleteNamespace(ctx, &servicediscovery.DeleteNamespaceInput{ - Id: aws.String(ids[0].id), - }) - if err != nil { - // This can only happen in the very corner case where someone is - // extremely fast in deleting this after we got its id above. - var oe *types.NamespaceNotFound - if errors.As(err, &oe) { - return sr.ErrNotFound - } - - return err - } - - l := h.log.WithName("DeleteNamespace") - - l.Info("waiting for operation to complete...") - if err := h.pollOperationStatus(aws.ToString(out.OperationId)); err != nil { - l.Info("operation completed with error") - return err - } - l.Info("operation completed successfully") - - return nil -} diff --git a/pkg/servregistry/aws/cloudmap/namespace_test.go b/pkg/servregistry/aws/cloudmap/namespace_test.go deleted file mode 100644 index 5a80fde..0000000 --- a/pkg/servregistry/aws/cloudmap/namespace_test.go +++ /dev/null @@ -1,552 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package cloudmap - -import ( - "context" - "fmt" - "testing" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery/types" - "github.com/stretchr/testify/assert" - ctrl "sigs.k8s.io/controller-runtime" -) - -func TestCreateNs(t *testing.T) { - cases := []struct { - h *Handler - ns *sr.Namespace - expRes *sr.Namespace - expErr error - }{ - { - expErr: sr.ErrNsNotProvided, - }, - { - ns: &sr.Namespace{}, - expErr: sr.ErrNsNameNotProvided, - }, - { - ns: &sr.Namespace{Name: "whatever"}, - h: &Handler{ - log: ctrl.Log.WithName("test"), - mainCtx: context.Background(), - Client: &fakeCloudMapClient{ - _CreateHttpNamespace: func(ctx context.Context, params *servicediscovery.CreateHttpNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreateHttpNamespaceOutput, error) { - return nil, &types.NamespaceAlreadyExists{} - }, - }, - }, - expErr: sr.ErrAlreadyExists, - }, - { - ns: &sr.Namespace{Name: "whatever"}, - h: &Handler{ - log: ctrl.Log.WithName("test"), - mainCtx: context.Background(), - Client: &fakeCloudMapClient{ - _CreateHttpNamespace: func(ctx context.Context, params *servicediscovery.CreateHttpNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreateHttpNamespaceOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - ns: &sr.Namespace{Name: "whatever", Metadata: map[string]string{"key": "val"}}, - h: &Handler{ - log: ctrl.Log.WithName("test"), - mainCtx: context.Background(), - Client: &fakeCloudMapClient{ - _CreateHttpNamespace: func(ctx context.Context, params *servicediscovery.CreateHttpNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreateHttpNamespaceOutput, error) { - if aws.ToString(params.Name) != "whatever" { - return nil, fmt.Errorf("provided namespace name is not correct") - } - if len(params.Tags) != 1 { - return nil, fmt.Errorf("provided tags length is not correct") - } - if aws.ToString(params.Tags[0].Key) != "key" || aws.ToString(params.Tags[0].Value) != "val" { - return nil, fmt.Errorf("provided tags are not correct") - } - - return &servicediscovery.CreateHttpNamespaceOutput{OperationId: aws.String("abc123")}, nil - }, - _GetOperation: func(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) { - if aws.ToString(params.OperationId) != "abc123" { - return nil, fmt.Errorf("wrong operation id provided") - } - return &servicediscovery.GetOperationOutput{Operation: &types.Operation{Status: types.OperationStatusFail, ErrorMessage: aws.String("whatever-error")}}, fmt.Errorf("whatever-error") - }, - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - ns: &sr.Namespace{Name: "whatever", Metadata: map[string]string{"key": "val"}}, - h: &Handler{ - log: ctrl.Log.WithName("test"), - mainCtx: context.Background(), - Client: &fakeCloudMapClient{ - _CreateHttpNamespace: func(ctx context.Context, params *servicediscovery.CreateHttpNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreateHttpNamespaceOutput, error) { - return &servicediscovery.CreateHttpNamespaceOutput{OperationId: aws.String("abc123")}, nil - }, - _GetOperation: func(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) { - return &servicediscovery.GetOperationOutput{Operation: &types.Operation{Status: types.OperationStatusSuccess}}, nil - }, - }, - }, - expRes: &sr.Namespace{Name: "whatever", Metadata: map[string]string{"key": "val"}}, - }, - } - - a := assert.New(t) - for i, c := range cases { - res, err := c.h.CreateNs(c.ns) - _ = res - - if !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestListOrGetNamespace(t *testing.T) { - cases := []struct { - cli cloudMapClientIface - nsName *string - expRes []*sr.Namespace - expIDs []*cloudMapIDs - expErr error - }{ - { - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - if len(params.Filters) != 0 { - return nil, fmt.Errorf("wrong length of filters provided") - } - - return &servicediscovery.ListNamespacesOutput{ - Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("ns-1")}, - {Arn: aws.String("arn-2"), Id: aws.String("id-2"), Name: aws.String("ns-2")}, - }, - }, nil - }, - _ListTagsForResource: func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expRes: []*sr.Namespace{ - { - Name: "ns-1", - Metadata: map[string]string{}, - }, - { - Name: "ns-2", - Metadata: map[string]string{}, - }, - }, - expIDs: []*cloudMapIDs{ - {arn: "arn-1", id: "id-1"}, - {arn: "arn-2", id: "id-2"}, - }, - }, - { - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{ - Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("ns-1")}, - {Arn: aws.String("arn-2"), Id: aws.String("id-2"), Name: aws.String("ns-2")}, - }, - }, nil - }, - _ListTagsForResource: func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - switch aws.ToString(params.ResourceARN) { - case "arn-1": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-1"), Value: aws.String("val-1")}}}, nil - case "arn-2": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-2"), Value: aws.String("val-2")}}}, nil - default: - return nil, fmt.Errorf("whatever-error") - } - }, - }, - expRes: []*sr.Namespace{ - { - Name: "ns-1", - Metadata: map[string]string{"key-1": "val-1"}, - }, - { - Name: "ns-2", - Metadata: map[string]string{"key-2": "val-2"}, - }, - }, - expIDs: []*cloudMapIDs{ - {arn: "arn-1", id: "id-1"}, - {arn: "arn-2", id: "id-2"}, - }, - }, - { - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{ - Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("ns-1")}, - {Arn: aws.String("arn-2"), Id: aws.String("id-2"), Name: aws.String("ns-2")}, - {Arn: aws.String("arn-3"), Id: aws.String("id-3"), Name: aws.String("ns-3")}, - }, - }, nil - }, - _ListTagsForResource: func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - switch aws.ToString(params.ResourceARN) { - case "arn-1": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-1"), Value: aws.String("val-1")}}}, nil - case "arn-2": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-2"), Value: aws.String("val-2")}}}, nil - case "arn-3": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-3"), Value: aws.String("val-3")}}}, nil - default: - return nil, fmt.Errorf("whatever-error") - } - }, - }, - expRes: []*sr.Namespace{ - { - Name: "ns-2", - Metadata: map[string]string{"key-2": "val-2"}, - }, - }, - expIDs: []*cloudMapIDs{ - {arn: "arn-2", id: "id-2"}, - }, - nsName: aws.String("ns-2"), - }, - } - - a := assert.New(t) - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - res, ids, err := h.listOrGetNamespace(c.nsName) - - if !a.Equal(c.expRes, res) || !a.Equal(c.expIDs, ids) || !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestGetNs(t *testing.T) { - cases := []struct { - cli cloudMapClientIface - name string - expRes *sr.Namespace - expErr error - }{ - { - expErr: sr.ErrNsNameNotProvided, - }, - { - name: "ns-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - name: "ns-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{}}, nil - }, - }, - expErr: sr.ErrNotFound, - }, - { - name: "ns-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("ns-1")}, - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("ns-1")}, - }}, nil - }, - _ListTagsForResource: func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - switch aws.ToString(params.ResourceARN) { - case "arn-1": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-1"), Value: aws.String("val-1")}}}, nil - case "arn-2": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-2"), Value: aws.String("val-2")}}}, nil - default: - return nil, fmt.Errorf("whatever-error") - } - }, - }, - expRes: &sr.Namespace{Name: "ns-1", Metadata: map[string]string{"key-1": "val-1"}}, - }, - } - - a := assert.New(t) - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - res, err := h.GetNs(c.name) - - if !a.Equal(c.expRes, res) || !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestUpdateNs(t *testing.T) { - cases := []struct { - cli cloudMapClientIface - ns *sr.Namespace - expRes *sr.Namespace - expErr error - }{ - { - expErr: sr.ErrNsNotProvided, - }, - { - ns: &sr.Namespace{}, - expErr: sr.ErrNsNameNotProvided, - }, - { - ns: &sr.Namespace{Name: "ns-1"}, - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - ns: &sr.Namespace{Name: "ns-1"}, - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{}}, nil - }, - }, - expErr: sr.ErrNotFound, - }, - { - ns: &sr.Namespace{Name: "ns-1"}, - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("ns-1")}, - }}, nil - }, - _ListTagsForResource: func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-1"), Value: aws.String("value-1")}}}, nil - }, - _TagResource: func(ctx context.Context, params *servicediscovery.TagResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.TagResourceOutput, error) { - return nil, &types.ResourceNotFoundException{} - }, - }, - expErr: sr.ErrNotFound, - }, - { - ns: &sr.Namespace{Name: "ns-1", Metadata: map[string]string{"new-key": "new-val"}}, - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("ns-1")}, - }}, nil - }, - _ListTagsForResource: func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-1"), Value: aws.String("value-1")}}}, nil - }, - _TagResource: func(ctx context.Context, params *servicediscovery.TagResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.TagResourceOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - ns: &sr.Namespace{Name: "ns-1", Metadata: map[string]string{"new-key": "new-val"}}, - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("ns-1")}, - }}, nil - }, - _ListTagsForResource: func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-1"), Value: aws.String("value-1")}}}, nil - }, - _TagResource: func(ctx context.Context, params *servicediscovery.TagResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.TagResourceOutput, error) { - if aws.ToString(params.ResourceARN) != "arn-1" { - return nil, fmt.Errorf("wrong arn provided") - } - if len(params.Tags) != 1 { - return nil, fmt.Errorf("wrong length of tags provided") - } - if aws.ToString(params.Tags[0].Key) != "new-key" || aws.ToString(params.Tags[0].Value) != "new-val" { - return nil, fmt.Errorf("wrong tags provided") - } - return &servicediscovery.TagResourceOutput{}, nil - }, - }, - expRes: &sr.Namespace{Name: "ns-1", Metadata: map[string]string{"new-key": "new-val"}}, - }, - } - - a := assert.New(t) - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - res, err := h.UpdateNs(c.ns) - - if !a.Equal(c.expRes, res) || !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestDeleteNs(t *testing.T) { - cases := []struct { - cli cloudMapClientIface - name string - expErr error - }{ - { - expErr: sr.ErrNsNameNotProvided, - }, - { - name: "ns-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - name: "ns-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{}}, nil - }, - }, - expErr: sr.ErrNotFound, - }, - { - name: "ns-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("ns-1")}, - }}, nil - }, - _ListTagsForResource: func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-1"), Value: aws.String("value-1")}}}, nil - }, - _DeleteNamespace: func(ctx context.Context, params *servicediscovery.DeleteNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteNamespaceOutput, error) { - return nil, &types.NamespaceNotFound{} - }, - }, - expErr: sr.ErrNotFound, - }, - { - name: "ns-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("ns-1")}, - }}, nil - }, - _ListTagsForResource: func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-1"), Value: aws.String("value-1")}}}, nil - }, - _DeleteNamespace: func(ctx context.Context, params *servicediscovery.DeleteNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteNamespaceOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - name: "ns-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("ns-1")}, - }}, nil - }, - _ListTagsForResource: func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-1"), Value: aws.String("value-1")}}}, nil - }, - _DeleteNamespace: func(ctx context.Context, params *servicediscovery.DeleteNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteNamespaceOutput, error) { - if aws.ToString(params.Id) != "id-1" { - return nil, fmt.Errorf("wrong id provided") - } - return &servicediscovery.DeleteNamespaceOutput{OperationId: aws.String("op-1")}, nil - }, - _GetOperation: func(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) { - if aws.ToString(params.OperationId) != "op-1" { - return nil, fmt.Errorf("wrong operation id provided") - } - return &servicediscovery.GetOperationOutput{Operation: &types.Operation{Status: types.OperationStatusFail, ErrorMessage: aws.String("whaterver-error")}}, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - name: "ns-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("ns-1")}, - }}, nil - }, - _ListTagsForResource: func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key-1"), Value: aws.String("value-1")}}}, nil - }, - _DeleteNamespace: func(ctx context.Context, params *servicediscovery.DeleteNamespaceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteNamespaceOutput, error) { - return &servicediscovery.DeleteNamespaceOutput{OperationId: aws.String("op-1")}, nil - }, - _GetOperation: func(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) { - return &servicediscovery.GetOperationOutput{Operation: &types.Operation{Status: types.OperationStatusSuccess}}, nil - }, - }, - }, - } - - a := assert.New(t) - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - if !a.Equal(c.expErr, h.DeleteNs(c.name)) { - a.FailNow("case failed", "case", i) - } - } -} diff --git a/pkg/servregistry/aws/cloudmap/service.go b/pkg/servregistry/aws/cloudmap/service.go deleted file mode 100644 index a6456cb..0000000 --- a/pkg/servregistry/aws/cloudmap/service.go +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package cloudmap - -import ( - "context" - "errors" - "time" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery/types" -) - -func (h *Handler) listOrGetService(nsName string, name *string) ([]*sr.Service, []*cloudMapIDs, error) { - // NOTE: as for other resources on Cloud Map, we cannot get a resource - // by its name but *only* with its AWS-generated ID. Thus, here too we - // need to actually search for the service rather than its name. Same - // reason why we got the namespace ID above. - _, ids, err := h.listOrGetNamespace(&nsName) - if err != nil { - return nil, nil, err - } - if len(ids) == 0 { - return nil, nil, sr.ErrNotFound - } - nsID := ids[0].id - - ctx, canc := context.WithTimeout(h.mainCtx, time.Minute) - defer canc() - - servs, err := h.Client.ListServices(ctx, &servicediscovery.ListServicesInput{ - Filters: []types.ServiceFilter{ - { - Name: types.ServiceFilterNameNamespaceId, - Values: []string{nsID}, - Condition: types.FilterConditionEq, - }, - }, - }) - if err != nil { - return nil, nil, err - } - - servList := []*sr.Service{} - servIDs := []*cloudMapIDs{} - for _, serv := range servs.Services { - if name != nil && aws.ToString(serv.Name) != *name { - // move on, this is not the service you're looking for. - continue - } - arn := aws.ToString(serv.Arn) - id := aws.ToString(serv.Id) - - servFound := &sr.Service{ - NsName: nsName, - Name: aws.ToString(serv.Name), - Metadata: map[string]string{}, - } - - servFound.Metadata = func() map[string]string { - tagCtx, tagCanc := context.WithTimeout(h.mainCtx, 30*time.Second) - defer tagCanc() - - tags, err := h.Client.ListTagsForResource(tagCtx, &servicediscovery.ListTagsForResourceInput{ - ResourceARN: serv.Arn, - }) - if err != nil { - h.log.WithName("ListTagsForResource").Info("error while getting tags", "error", err, "name", servFound.Name) - return map[string]string{} - } - - return fromTagsSliceToMap(tags.Tags) - }() - - if name != nil { - // if you're here, it means that you are indeed the service we - // are looking for. - return []*sr.Service{servFound}, []*cloudMapIDs{{arn, id}}, nil - } - - servList = append(servList, servFound) - servIDs = append(servIDs, &cloudMapIDs{arn, id}) - } - - return servList, servIDs, nil -} - -// GetServ returns the service if exists. -func (h *Handler) GetServ(nsName, servName string) (*sr.Service, error) { - if nsName == "" { - return nil, sr.ErrNsNameNotProvided - } - if servName == "" { - return nil, sr.ErrServNameNotProvided - } - - // -- then get the service - servs, _, err := h.listOrGetService(nsName, &servName) - if err != nil { - return nil, err - } - if len(servs) == 0 { - return nil, sr.ErrNotFound - } - - return servs[0], nil -} - -// ListServ returns a list of services inside the provided namespace. -func (h *Handler) ListServ(nsName string) (servList []*sr.Service, err error) { - if nsName == "" { - return nil, sr.ErrNsNameNotProvided - } - - servs, _, err := h.listOrGetService(nsName, nil) - if err != nil { - return nil, err - } - - return servs, nil -} - -// CreateServ creates the service. -func (h *Handler) CreateServ(serv *sr.Service) (*sr.Service, error) { - if serv == nil { - return nil, sr.ErrServNotProvided - } - if serv.NsName == "" { - return nil, sr.ErrNsNameNotProvided - } - if serv.Name == "" { - return nil, sr.ErrServNameNotProvided - } - - _, ids, err := h.listOrGetNamespace(&serv.NsName) - if err != nil { - return nil, err - } - if len(ids) == 0 { - return nil, sr.ErrNotFound - } - nsID := ids[0].id - - ctx, canc := context.WithTimeout(h.mainCtx, time.Minute) - defer canc() - - _, err = h.Client.CreateService(ctx, &servicediscovery.CreateServiceInput{ - Name: aws.String(serv.Name), - NamespaceId: aws.String(nsID), - Tags: fromMapToTagsSlice(serv.Metadata), - Type: types.ServiceTypeOptionHttp, - }) - if err == nil { - return serv, nil - } - - // -- the probability of this occurring is very rare but we're handling - // this anyways - var oe *types.NamespaceNotFound - if errors.As(err, &oe) { - return nil, sr.ErrNotFound - } - - var os *types.ServiceAlreadyExists - if errors.As(err, &os) { - return nil, sr.ErrAlreadyExists - } - - // any other error - return nil, err -} - -// UpdateServ updates the service. -func (h *Handler) UpdateServ(serv *sr.Service) (*sr.Service, error) { - if serv == nil { - return nil, sr.ErrServNotProvided - } - if serv.NsName == "" { - return nil, sr.ErrNsNameNotProvided - } - if serv.Name == "" { - return nil, sr.ErrServNameNotProvided - } - - _, servIDs, err := h.listOrGetService(serv.NsName, &serv.Name) - if err != nil { - return nil, err - } - if len(servIDs) == 0 { - return nil, sr.ErrNotFound - } - - err = h.tagResource(servIDs[0].arn, fromMapToTagsSlice(serv.Metadata)) - if err == nil { - return serv, nil - } - - // -- the probability of occurring is very rare but we're - // handling it anyways - var oe *types.NamespaceNotFound - if errors.As(err, &oe) { - return nil, sr.ErrNotFound - } - - var os *types.ServiceAlreadyExists - if errors.As(err, &os) { - return nil, sr.ErrAlreadyExists - } - - // any other error - return nil, err -} - -// DeleteServ deletes the service. -func (h *Handler) DeleteServ(nsName, servName string) error { - if nsName == "" { - return sr.ErrNsNameNotProvided - } - if servName == "" { - return sr.ErrServNameNotProvided - } - - _, servIDs, err := h.listOrGetService(nsName, &servName) - if err != nil { - return err - } - if len(servIDs) == 0 { - return sr.ErrNotFound - } - servID := servIDs[0].id - - ctx, canc := context.WithTimeout(h.mainCtx, time.Minute) - defer canc() - - _, err = h.Client.DeleteService(ctx, &servicediscovery.DeleteServiceInput{ - Id: aws.String(servID), - }) - if err == nil { - return nil - } - - var oe *types.ServiceNotFound - if errors.As(err, &oe) { - return sr.ErrNotFound - } - - // any other error - return err -} diff --git a/pkg/servregistry/aws/cloudmap/service_test.go b/pkg/servregistry/aws/cloudmap/service_test.go deleted file mode 100644 index 9b6a3ad..0000000 --- a/pkg/servregistry/aws/cloudmap/service_test.go +++ /dev/null @@ -1,790 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package cloudmap - -import ( - "context" - "fmt" - "testing" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery/types" - "github.com/stretchr/testify/assert" - ctrl "sigs.k8s.io/controller-runtime" -) - -func TestListOrGetService(t *testing.T) { - listNamespaces := func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{ - Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("ns-arn-1"), Id: aws.String("ns-id-1"), Name: aws.String("ns-1")}, - {Arn: aws.String("ns-arn-2"), Id: aws.String("ns-id-2"), Name: aws.String("ns-2")}, - {Arn: aws.String("ns-arn-3"), Id: aws.String("ns-id-3"), Name: aws.String("ns-3")}, - }, - }, nil - } - listTagsForResource := func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - switch aws.ToString(params.ResourceARN) { - case "ns-arn-1", "ns-arn-2", "ns-arn-3", "serv-arn-1", "serv-arn-2", "serv-arn-3": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key"), Value: aws.String("value")}}}, nil - default: - return nil, fmt.Errorf("whatever-error") - } - } - - cases := []struct { - name *string - cli cloudMapClientIface - expRes []*sr.Service - expIDs []*cloudMapIDs - expErr error - }{ - { - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - _ListTagsForResource: listTagsForResource, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{}}, nil - }, - _ListTagsForResource: listTagsForResource, - }, - expErr: sr.ErrNotFound, - }, - { - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _ListServices: func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListServices: func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - if len(params.Filters) != 1 { - return nil, fmt.Errorf("wrong number of filters") - } - ffilter := params.Filters[0] - if ffilter.Name != types.ServiceFilterNameNamespaceId || ffilter.Condition != types.FilterConditionEq || ffilter.Values[0] != "ns-id-1" { - return nil, fmt.Errorf("wrong filters passed") - } - - return &servicediscovery.ListServicesOutput{ - Services: []types.ServiceSummary{ - {Arn: aws.String("arn-1"), Id: aws.String("id-1"), Name: aws.String("serv-1")}, - {Arn: aws.String("arn-2"), Id: aws.String("id-2"), Name: aws.String("serv-2")}, - {Arn: aws.String("arn-3"), Id: aws.String("id-3"), Name: aws.String("serv-3")}, - }, - }, nil - }, - _ListTagsForResource: func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expRes: []*sr.Service{ - {Name: "serv-1", NsName: "ns-1", Metadata: map[string]string{}}, - {Name: "serv-2", NsName: "ns-1", Metadata: map[string]string{}}, - {Name: "serv-3", NsName: "ns-1", Metadata: map[string]string{}}, - }, - expIDs: []*cloudMapIDs{ - {arn: "arn-1", id: "id-1"}, - {arn: "arn-2", id: "id-2"}, - {arn: "arn-3", id: "id-3"}, - }, - }, - { - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListServices: func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - if len(params.Filters) != 1 { - return nil, fmt.Errorf("wrong number of filters") - } - ffilter := params.Filters[0] - if ffilter.Name != types.ServiceFilterNameNamespaceId || ffilter.Condition != types.FilterConditionEq || ffilter.Values[0] != "ns-id-1" { - return nil, fmt.Errorf("wrong filters passed") - } - - return &servicediscovery.ListServicesOutput{ - Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-1"), Id: aws.String("serv-id-1"), Name: aws.String("serv-1")}, - {Arn: aws.String("serv-arn-2"), Id: aws.String("serv-id-2"), Name: aws.String("serv-2")}, - {Arn: aws.String("serv-arn-3"), Id: aws.String("serv-id-3"), Name: aws.String("serv-3")}, - }, - }, nil - }, - _ListTagsForResource: listTagsForResource, - }, - expRes: []*sr.Service{ - {Name: "serv-1", NsName: "ns-1", Metadata: map[string]string{"key": "value"}}, - {Name: "serv-2", NsName: "ns-1", Metadata: map[string]string{"key": "value"}}, - {Name: "serv-3", NsName: "ns-1", Metadata: map[string]string{"key": "value"}}, - }, - expIDs: []*cloudMapIDs{ - {arn: "serv-arn-1", id: "serv-id-1"}, - {arn: "serv-arn-2", id: "serv-id-2"}, - {arn: "serv-arn-3", id: "serv-id-3"}, - }, - }, - { - name: aws.String("serv-2"), - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListServices: func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-1"), Id: aws.String("serv-id-1"), Name: aws.String("serv-1")}, - {Arn: aws.String("serv-arn-2"), Id: aws.String("serv-id-2"), Name: aws.String("serv-2")}, - {Arn: aws.String("serv-arn-3"), Id: aws.String("serv-id-3"), Name: aws.String("serv-3")}, - }}, nil - }, - _ListTagsForResource: listTagsForResource, - }, - - expRes: []*sr.Service{ - {Name: "serv-2", NsName: "ns-1", Metadata: map[string]string{"key": "value"}}, - }, - expIDs: []*cloudMapIDs{ - {arn: "serv-arn-2", id: "serv-id-2"}, - }, - }, - } - - a := assert.New(t) - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - res, ids, err := h.listOrGetService("ns-1", c.name) - - if !a.Equal(c.expRes, res) || !a.Equal(c.expIDs, ids) || !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestGetServ(t *testing.T) { - // prepare the testing environment - listNamespaces := func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("ns-arn-1"), Id: aws.String("ns-id-1"), Name: aws.String("ns-1")}, - {Arn: aws.String("ns-arn-2"), Id: aws.String("ns-id-2"), Name: aws.String("ns-2")}, - {Arn: aws.String("ns-arn-3"), Id: aws.String("ns-id-3"), Name: aws.String("ns-3")}, - }}, nil - } - listServices := func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-1"), Id: aws.String("serv-id-1"), Name: aws.String("serv-1")}, - {Arn: aws.String("serv-arn-2"), Id: aws.String("serv-id-2"), Name: aws.String("serv-2")}, - {Arn: aws.String("serv-arn-3"), Id: aws.String("serv-id-3"), Name: aws.String("serv-3")}, - }}, nil - } - listTagsForResource := func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - switch aws.ToString(params.ResourceARN) { - case "ns-arn-1", "ns-arn-2", "ns-arn-3", "serv-arn-1", "serv-arn-2", "serv-arn-3": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key"), Value: aws.String("value")}}}, nil - default: - return nil, fmt.Errorf("whatever-error") - } - } - - cases := []struct { - nsName string - servName string - cli cloudMapClientIface - expRes *sr.Service - expErr error - }{ - { - expErr: sr.ErrNsNameNotProvided, - }, - { - nsName: "ns-1", - expErr: sr.ErrServNameNotProvided, - }, - { - nsName: "ns-1", - servName: "serv-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - nsName: "ns-4", - servName: "serv-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - }, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _ListServices: func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - nsName: "ns-1", - servName: "serv-4", - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _ListServices: listServices, - }, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _ListServices: listServices, - }, - expRes: &sr.Service{Name: "serv-1", NsName: "ns-1", Metadata: map[string]string{"key": "value"}}, - }, - } - - a := assert.New(t) - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - res, err := h.GetServ(c.nsName, c.servName) - - if !a.Equal(c.expRes, res) || !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestListServ(t *testing.T) { - // prepare the testing environment - listNamespaces := func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("ns-arn-1"), Id: aws.String("ns-id-1"), Name: aws.String("ns-1")}, - {Arn: aws.String("ns-arn-2"), Id: aws.String("ns-id-2"), Name: aws.String("ns-2")}, - {Arn: aws.String("ns-arn-3"), Id: aws.String("ns-id-3"), Name: aws.String("ns-3")}, - }}, nil - } - listServices := func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - switch params.Filters[0].Values[0] { - case "ns-id-1": - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-1"), Id: aws.String("serv-id-1"), Name: aws.String("serv-1")}, - {Arn: aws.String("serv-arn-2"), Id: aws.String("serv-id-2"), Name: aws.String("serv-2")}, - }}, nil - case "ns-id-2": - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-3"), Id: aws.String("serv-id-3"), Name: aws.String("serv-3")}, - }}, nil - default: - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{}}, nil - } - } - listTagsForResource := func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - switch aws.ToString(params.ResourceARN) { - case "ns-arn-1", "ns-arn-2", "ns-arn-3", "serv-arn-1", "serv-arn-2", "serv-arn-3": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key"), Value: aws.String("value")}}}, nil - default: - return nil, fmt.Errorf("whatever-error") - } - } - - cases := []struct { - nsName string - cli cloudMapClientIface - expRes []*sr.Service - expErr error - }{ - { - expErr: sr.ErrNsNameNotProvided, - }, - { - nsName: "ns-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - nsName: "ns-4", - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - }, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _ListServices: func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - nsName: "ns-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _ListServices: listServices, - }, - expRes: []*sr.Service{ - {Name: "serv-1", NsName: "ns-1", Metadata: map[string]string{"key": "value"}}, - {Name: "serv-2", NsName: "ns-1", Metadata: map[string]string{"key": "value"}}, - }, - }, - } - - a := assert.New(t) - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - res, err := h.ListServ(c.nsName) - - if !a.Equal(c.expRes, res) || !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestCreateServ(t *testing.T) { - // prepare the testing environment - listNamespaces := func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("ns-arn-1"), Id: aws.String("ns-id-1"), Name: aws.String("ns-1")}, - {Arn: aws.String("ns-arn-2"), Id: aws.String("ns-id-2"), Name: aws.String("ns-2")}, - {Arn: aws.String("ns-arn-3"), Id: aws.String("ns-id-3"), Name: aws.String("ns-3")}, - }}, nil - } - createServ := func(ctx context.Context, params *servicediscovery.CreateServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreateServiceOutput, error) { - switch aws.ToString(params.Name) { - case "serv-1": - return nil, &types.NamespaceNotFound{} - case "serv-2": - return nil, &types.ServiceAlreadyExists{} - case "serv-3": - return nil, fmt.Errorf("whatever-error") - default: - return &servicediscovery.CreateServiceOutput{}, nil - } - } - listTagsForResource := func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - switch aws.ToString(params.ResourceARN) { - case "ns-arn-1", "ns-arn-2", "ns-arn-3", "serv-arn-1", "serv-arn-2", "serv-arn-3": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key"), Value: aws.String("value")}}}, nil - default: - return nil, fmt.Errorf("whatever-error") - } - } - - a := assert.New(t) - cases := []struct { - serv *sr.Service - cli cloudMapClientIface - expRes *sr.Service - expErr error - }{ - { - expErr: sr.ErrServNotProvided, - }, - { - serv: &sr.Service{}, - expErr: sr.ErrNsNameNotProvided, - }, - { - serv: &sr.Service{NsName: "ns-1"}, - expErr: sr.ErrServNameNotProvided, - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-1"}, - cli: &fakeCloudMapClient{_ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, _CreateService: createServ, _ListTagsForResource: listTagsForResource}, - expErr: fmt.Errorf("whatever-error"), - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-1"}, - cli: &fakeCloudMapClient{_ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{}}, nil - }, _CreateService: createServ, _ListTagsForResource: listTagsForResource}, - expErr: sr.ErrNotFound, - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-1"}, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _CreateService: createServ, _ListTagsForResource: listTagsForResource}, - expErr: sr.ErrNotFound, - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-2"}, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _CreateService: createServ, _ListTagsForResource: listTagsForResource}, - expErr: sr.ErrAlreadyExists, - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-3"}, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _CreateService: createServ, _ListTagsForResource: listTagsForResource}, - expErr: fmt.Errorf("whatever-error"), - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-4", Metadata: map[string]string{"key": "value"}}, - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _CreateService: func(ctx context.Context, params *servicediscovery.CreateServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.CreateServiceOutput, error) { - // check that we are sending the right values - if aws.ToString(params.Name) != "serv-4" { - return nil, fmt.Errorf("wrong service name provided") - } - if aws.ToString(params.NamespaceId) != "ns-id-1" { - return nil, fmt.Errorf("wrong namespace id provided") - } - if len(params.Tags) != 1 { - return nil, fmt.Errorf("wrong number of tags provided") - } - if params.Type != types.ServiceTypeOptionHttp { - return nil, fmt.Errorf("wrong service type provided") - } - if aws.ToString(params.Tags[0].Key) != "key" || aws.ToString(params.Tags[0].Value) != "value" { - return nil, fmt.Errorf("wrong tags provided") - } - - return createServ(ctx, params, optFns...) - }, - }, - expRes: &sr.Service{NsName: "ns-1", Name: "serv-4", Metadata: map[string]string{"key": "value"}}, - }, - } - - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - res, err := h.CreateServ(c.serv) - - if !a.Equal(c.expRes, res) || !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestUpdateServ(t *testing.T) { - // prepare the testing environment - listNamespaces := func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("ns-arn-1"), Id: aws.String("ns-id-1"), Name: aws.String("ns-1")}, - {Arn: aws.String("ns-arn-2"), Id: aws.String("ns-id-2"), Name: aws.String("ns-2")}, - {Arn: aws.String("ns-arn-3"), Id: aws.String("ns-id-3"), Name: aws.String("ns-3")}, - }}, nil - } - listServices := func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - switch params.Filters[0].Values[0] { - case "ns-id-1": - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-1"), Id: aws.String("serv-id-1"), Name: aws.String("serv-1")}, - {Arn: aws.String("serv-arn-2"), Id: aws.String("serv-id-2"), Name: aws.String("serv-2")}, - }}, nil - case "ns-id-2": - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-3"), Id: aws.String("serv-id-3"), Name: aws.String("serv-3")}, - }}, nil - default: - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{}}, nil - } - } - listTagsForResource := func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - switch aws.ToString(params.ResourceARN) { - case "ns-arn-1", "ns-arn-2", "ns-arn-3", "serv-arn-1", "serv-arn-2", "serv-arn-3": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key"), Value: aws.String("value")}}}, nil - default: - return nil, fmt.Errorf("whatever-error") - } - } - - a := assert.New(t) - cases := []struct { - serv *sr.Service - cli cloudMapClientIface - expRes *sr.Service - expErr error - }{ - { - expErr: sr.ErrServNotProvided, - }, - { - serv: &sr.Service{}, - expErr: sr.ErrNsNameNotProvided, - }, - { - serv: &sr.Service{NsName: "ns-1"}, - expErr: sr.ErrServNameNotProvided, - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-1"}, - cli: &fakeCloudMapClient{_ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, _ListTagsForResource: listTagsForResource}, - expErr: fmt.Errorf("whatever-error"), - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-1"}, - cli: &fakeCloudMapClient{_ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{}}, nil - }, _ListTagsForResource: listTagsForResource}, - expErr: sr.ErrNotFound, - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-1"}, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, - _ListServices: func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }}, - expErr: fmt.Errorf("whatever-error"), - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-4"}, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices}, - expErr: sr.ErrNotFound, - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-1", Metadata: map[string]string{"key-1": "value-1"}}, - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _ListServices: listServices, - _TagResource: func(ctx context.Context, params *servicediscovery.TagResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.TagResourceOutput, error) { - if aws.ToString(params.ResourceARN) != "serv-arn-1" { - return nil, fmt.Errorf("sent-wrong-arn") - } - if len(params.Tags) != 1 { - return nil, fmt.Errorf("wrong-number-of-tags") - } - if aws.ToString(params.Tags[0].Key) != "key-1" && aws.ToString(params.Tags[0].Value) != "value-1" && - aws.ToString(params.Tags[1].Key) != "key-2" && aws.ToString(params.Tags[1].Value) != "value-2" { - return nil, fmt.Errorf("wrong-tags") - } - - return &servicediscovery.TagResourceOutput{}, nil - }}, - expRes: &sr.Service{NsName: "ns-1", Name: "serv-1", Metadata: map[string]string{"key-1": "value-1"}}, - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-1"}, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices, - _TagResource: func(ctx context.Context, params *servicediscovery.TagResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.TagResourceOutput, error) { - return nil, &types.NamespaceNotFound{} - }, - }, - expErr: sr.ErrNotFound, - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-1"}, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices, - _TagResource: func(ctx context.Context, params *servicediscovery.TagResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.TagResourceOutput, error) { - return nil, &types.ServiceAlreadyExists{} - }, - }, - expErr: sr.ErrAlreadyExists, - }, - { - serv: &sr.Service{NsName: "ns-1", Name: "serv-1"}, - cli: &fakeCloudMapClient{_ListNamespaces: listNamespaces, _ListTagsForResource: listTagsForResource, _ListServices: listServices, - _TagResource: func(ctx context.Context, params *servicediscovery.TagResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.TagResourceOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - } - - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - res, err := h.UpdateServ(c.serv) - - if !a.Equal(c.expRes, res) || !a.Equal(c.expErr, err) { - a.FailNow("case failed", "case", i) - } - } -} - -func TestDeleteServ(t *testing.T) { - // prepare the testing environment - listNamespaces := func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ - {Arn: aws.String("ns-arn-1"), Id: aws.String("ns-id-1"), Name: aws.String("ns-1")}, - {Arn: aws.String("ns-arn-2"), Id: aws.String("ns-id-2"), Name: aws.String("ns-2")}, - {Arn: aws.String("ns-arn-3"), Id: aws.String("ns-id-3"), Name: aws.String("ns-3")}, - }}, nil - } - listServices := func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - switch params.Filters[0].Values[0] { - case "ns-id-1": - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-1"), Id: aws.String("serv-id-1"), Name: aws.String("serv-1")}, - {Arn: aws.String("serv-arn-2"), Id: aws.String("serv-id-2"), Name: aws.String("serv-2")}, - }}, nil - case "ns-id-2": - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{ - {Arn: aws.String("serv-arn-3"), Id: aws.String("serv-id-3"), Name: aws.String("serv-3")}, - }}, nil - default: - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{}}, nil - } - } - listTagsForResource := func(ctx context.Context, params *servicediscovery.ListTagsForResourceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListTagsForResourceOutput, error) { - switch aws.ToString(params.ResourceARN) { - case "ns-arn-1", "ns-arn-2", "ns-arn-3", "serv-arn-1", "serv-arn-2", "serv-arn-3": - return &servicediscovery.ListTagsForResourceOutput{Tags: []types.Tag{{Key: aws.String("key"), Value: aws.String("value")}}}, nil - default: - return nil, fmt.Errorf("whatever-error") - } - } - - a := assert.New(t) - cases := []struct { - nsName string - servName string - cli cloudMapClientIface - expErr error - }{ - { - expErr: sr.ErrNsNameNotProvided, - }, - { - nsName: "ns-1", - expErr: sr.ErrServNameNotProvided, - }, - { - nsName: "ns-1", - servName: "serv-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - nsName: "ns-1", - servName: "serv-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: func(ctx context.Context, params *servicediscovery.ListNamespacesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListNamespacesOutput, error) { - return &servicediscovery.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{}}, nil - }, - }, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _ListServices: func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - nsName: "ns-1", - servName: "serv-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _ListServices: func(ctx context.Context, params *servicediscovery.ListServicesInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.ListServicesOutput, error) { - return &servicediscovery.ListServicesOutput{Services: []types.ServiceSummary{}}, nil - }, - }, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _ListServices: listServices, - _DeleteService: func(ctx context.Context, params *servicediscovery.DeleteServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteServiceOutput, error) { - return nil, fmt.Errorf("whatever-error") - }, - }, - expErr: fmt.Errorf("whatever-error"), - }, - { - nsName: "ns-1", - servName: "serv-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _ListServices: listServices, - _DeleteService: func(ctx context.Context, params *servicediscovery.DeleteServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteServiceOutput, error) { - return nil, &types.ServiceNotFound{} - }, - }, - expErr: sr.ErrNotFound, - }, - { - nsName: "ns-1", - servName: "serv-1", - cli: &fakeCloudMapClient{ - _ListNamespaces: listNamespaces, - _ListTagsForResource: listTagsForResource, - _ListServices: listServices, - _DeleteService: func(ctx context.Context, params *servicediscovery.DeleteServiceInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.DeleteServiceOutput, error) { - if aws.ToString(params.Id) != "serv-id-1" { - return nil, fmt.Errorf("wrong service id provided") - } - return &servicediscovery.DeleteServiceOutput{}, nil - }, - }, - }, - } - - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - - if !a.Equal(c.expErr, h.DeleteServ(c.nsName, c.servName)) { - a.FailNow("case failed", "case", i) - } - } -} diff --git a/pkg/servregistry/aws/cloudmap/utils.go b/pkg/servregistry/aws/cloudmap/utils.go deleted file mode 100644 index 1cf4ae9..0000000 --- a/pkg/servregistry/aws/cloudmap/utils.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package cloudmap - -import ( - "context" - "fmt" - "time" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery/types" -) - -func fromTagsSliceToMap(tags []types.Tag) map[string]string { - metadata := map[string]string{} - - for _, t := range tags { - metadata[aws.ToString(t.Key)] = aws.ToString(t.Value) - } - - return metadata -} - -func fromMapToTagsSlice(metadata map[string]string) []types.Tag { - tags := []types.Tag{} - - for k, v := range metadata { - tags = append(tags, types.Tag{Key: aws.String(k), Value: aws.String(v)}) - } - return tags -} - -func (h *Handler) pollOperationStatus(operationID string) error { - ticker := time.NewTicker(pollOperationFrequency) - for { - select { - case <-h.mainCtx.Done(): - h.log.Info("context canceled: stopping checking for operation status") - return nil - case <-ticker.C: - opCtx, opCanc := context.WithTimeout(h.mainCtx, 3*time.Second) - op, err := h.Client.GetOperation(opCtx, &servicediscovery.GetOperationInput{OperationId: aws.String(operationID)}) - if err != nil { - opCanc() - return err - } - opCanc() - - if op.Operation.Status == types.OperationStatusPending || op.Operation.Status == types.OperationStatusSubmitted { - h.log.Info("operation not completed yet") - continue - } - - if op.Operation.Status == types.OperationStatusFail { - return fmt.Errorf(aws.ToString(op.Operation.ErrorMessage)) - } - - return nil - } - } -} - -func (h *Handler) tagResource(arn string, tags []types.Tag) error { - ctx, canc := context.WithTimeout(h.mainCtx, time.Minute) - defer canc() - - // NOTE: this won't replace all tags apparently: if you have annotations - // A, B and C on Cloud Map and want to just write A and B, I am not - // entirely sure that C will be deleted by using this function. - // Nonetheless, we don't register annotations if the user doesn't want - // them, so for now this is good. - _, err := h.Client.TagResource(ctx, &servicediscovery.TagResourceInput{ - ResourceARN: aws.String(arn), - Tags: tags, - }) - - return err -} diff --git a/pkg/servregistry/aws/cloudmap/utils_test.go b/pkg/servregistry/aws/cloudmap/utils_test.go deleted file mode 100644 index 5c67a2b..0000000 --- a/pkg/servregistry/aws/cloudmap/utils_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package cloudmap - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery" - "github.com/aws/aws-sdk-go-v2/service/servicediscovery/types" - "github.com/stretchr/testify/assert" - ctrl "sigs.k8s.io/controller-runtime" -) - -func TestPollOperationStatus(t *testing.T) { - pollOperationFrequency = time.Millisecond - cases := []struct { - cli cloudMapClientIface - expError error - }{ - { - cli: func() cloudMapClientIface { - h := &fakeCloudMapClient{} - h._GetOperation = func(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) { - return nil, fmt.Errorf("whatever-error") - } - return h - }(), - expError: fmt.Errorf("whatever-error"), - }, - { - cli: func() cloudMapClientIface { - pollCount := 0 - h := &fakeCloudMapClient{} - h._GetOperation = func(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) { - if pollCount == 0 { - pollCount++ - return &servicediscovery.GetOperationOutput{Operation: &types.Operation{Status: types.OperationStatusPending}}, nil - } - return &servicediscovery.GetOperationOutput{Operation: &types.Operation{Status: types.OperationStatusFail, ErrorMessage: aws.String("whatever-error")}}, nil - } - return h - }(), - expError: fmt.Errorf("whatever-error"), - }, - { - cli: func() cloudMapClientIface { - h := &fakeCloudMapClient{} - h._GetOperation = func(ctx context.Context, params *servicediscovery.GetOperationInput, optFns ...func(*servicediscovery.Options)) (*servicediscovery.GetOperationOutput, error) { - return &servicediscovery.GetOperationOutput{Operation: &types.Operation{Status: types.OperationStatusSuccess}}, nil - } - return h - }(), - }, - } - - a := assert.New(t) - for i, c := range cases { - h := &Handler{Client: c.cli, mainCtx: context.Background(), log: ctrl.Log.WithName("test")} - err := h.pollOperationStatus("whatever") - - if !a.Equal(c.expError, err) { - a.FailNow("case failed", "case", i) - } - } -} diff --git a/pkg/servregistry/broker.go b/pkg/servregistry/broker.go deleted file mode 100644 index df66c10..0000000 --- a/pkg/servregistry/broker.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servregistry - -import ( - "sync" - - "github.com/go-logr/logr" - "sigs.k8s.io/controller-runtime/pkg/log/zap" -) - -const ( - defOpKey = "owner" - defOpVal = "cnwan-operator" -) - -// This file contains the definition of the Broker struct. - -// Broker is a structure that acts as an intermediary, setting up data - i.e. -// namespaces, services and endpoints - and performing checks before calling -// the appropriate functions of the service registry. -// -// Its functions are split on namespace.go, service.go and endpoint.go to -// make the package more readable. -type Broker struct { - Reg ServiceRegistry - log logr.Logger - - opMetaPair MetadataPair - persistentMeta []MetadataPair - lock sync.Mutex -} - -// MetadataPair represents a key-value pair that is/will be registered in a -// service registry. -type MetadataPair struct { - // Key of the metadata - Key string - // Value of the metadata - Value string -} - -// NewBroker returns a new instance of service registry broker. -// -// An error is returned in case no service registry where to perform operations -// is provided. -func NewBroker(reg ServiceRegistry, opMetaPair MetadataPair, persMeta ...MetadataPair) (*Broker, error) { - // Validation and inits - l := zap.New(zap.UseDevMode(true)).WithName("ServiceRegistryBroker") - - if reg == nil { - return nil, ErrServRegNotProvided - } - - if opMetaPair.Key == "" { - opMetaPair.Key = defOpKey - } - if opMetaPair.Value == "" { - opMetaPair.Value = defOpVal - } - - return &Broker{ - log: l, - Reg: reg, - opMetaPair: opMetaPair, - persistentMeta: persMeta, - }, nil -} diff --git a/pkg/servregistry/broker_test.go b/pkg/servregistry/broker_test.go deleted file mode 100644 index 06130c9..0000000 --- a/pkg/servregistry/broker_test.go +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servregistry - -import ( - "errors" - "testing" - - a "github.com/stretchr/testify/assert" - corev1 "k8s.io/api/core/v1" -) - -type fakeServReg struct { - nsList map[string]*Namespace - servList map[string]*Service - endpList map[string]*Endpoint - - createdNs []string - updatedNs []string - deletedNs []string - - createdServ []string - updatedServ []string - deletedServ []string - - createdEndp []string - updatedEndp []string - deletedEndp []string -} - -func newFakeInt() ServiceRegistry { - return &fakeServReg{ - nsList: map[string]*Namespace{}, - servList: map[string]*Service{}, - endpList: map[string]*Endpoint{}, - createdNs: []string{}, - updatedNs: []string{}, - deletedNs: []string{}, - createdServ: []string{}, - updatedServ: []string{}, - deletedServ: []string{}, - createdEndp: []string{}, - updatedEndp: []string{}, - deletedEndp: []string{}, - } -} - -func newFakeStruct() *fakeServReg { - return &fakeServReg{ - nsList: map[string]*Namespace{}, - servList: map[string]*Service{}, - endpList: map[string]*Endpoint{}, - createdNs: []string{}, - updatedNs: []string{}, - deletedNs: []string{}, - createdServ: []string{}, - updatedServ: []string{}, - deletedServ: []string{}, - createdEndp: []string{}, - updatedEndp: []string{}, - deletedEndp: []string{}, - } -} - -func (f *fakeServReg) GetNs(name string) (*Namespace, error) { - if name == "get-error" { - return nil, errors.New("error") - } - - ns, exists := f.nsList[name] - if !exists { - return nil, ErrNotFound - } - - return ns, nil -} - -func (f *fakeServReg) ListNs() ([]*Namespace, error) { - if _, exists := f.nsList["list-error"]; exists { - return nil, errors.New("error") - } - - list := []*Namespace{} - for _, n := range f.nsList { - list = append(list, n) - } - - return list, nil -} - -func (f *fakeServReg) CreateNs(ns *Namespace) (*Namespace, error) { - if ns.Name == "create-error" { - return nil, errors.New("error") - } - - _, exists := f.nsList[ns.Name] - if exists { - return nil, ErrAlreadyExists - } - - f.nsList[ns.Name] = ns - - return f.nsList[ns.Name], nil -} - -func (f *fakeServReg) UpdateNs(ns *Namespace) (*Namespace, error) { - if ns.Name == "update-error" { - return nil, errors.New("error") - } - - _, exists := f.nsList[ns.Name] - if !exists { - return nil, ErrNotFound - } - - f.nsList[ns.Name] = ns - f.updatedNs = append(f.updatedEndp, ns.Name) - - return f.nsList[ns.Name], nil -} - -func (f *fakeServReg) DeleteNs(nsName string) error { - if nsName == "delete-error" { - return errors.New("error") - } - - _, exists := f.nsList[nsName] - if !exists { - return ErrNotFound - } - - delete(f.nsList, nsName) - f.deletedNs = append(f.deletedNs, nsName) - - del := []string{} - for sname, s := range f.servList { - if s.NsName == nsName { - del = append(del, sname) - } - } - - for _, sname := range del { - delete(f.servList, sname) - f.deletedServ = append(f.deletedServ, sname) - } - - return nil -} - -func (f *fakeServReg) GetServ(nsName, servName string) (*Service, error) { - if servName == "get-error" { - return nil, errors.New("error") - } - - serv, exists := f.servList[servName] - if !exists { - return nil, ErrNotFound - } - - return serv, nil -} - -func (f *fakeServReg) ListServ(nsName string) ([]*Service, error) { - if _, exists := f.servList["list-error"]; exists { - return nil, errors.New("error") - } - - list := []*Service{} - for _, s := range f.servList { - if s.NsName == nsName { - list = append(list, s) - } - } - - return list, nil -} - -func (f *fakeServReg) CreateServ(serv *Service) (*Service, error) { - if serv.Name == "create-error" { - return nil, errors.New("error") - } - - _, exists := f.servList[serv.Name] - if exists { - return nil, ErrAlreadyExists - } - - f.servList[serv.Name] = serv - f.createdServ = append(f.createdServ, serv.Name) - - return f.servList[serv.Name], nil -} - -func (f *fakeServReg) UpdateServ(serv *Service) (*Service, error) { - if serv.Name == "update-error" { - return nil, errors.New("error") - } - - _, exists := f.servList[serv.Name] - if !exists { - return nil, ErrNotFound - } - - f.servList[serv.Name] = serv - f.updatedServ = append(f.updatedServ, serv.Name) - - return f.servList[serv.Name], nil -} - -func (f *fakeServReg) DeleteServ(nsName, servName string) error { - if servName == "delete-error" { - return errors.New("error") - } - - _, exists := f.servList[servName] - if !exists { - return ErrNotFound - } - - delete(f.servList, nsName) - f.deletedServ = append(f.deletedServ, servName) - - del := []string{} - for ename, e := range f.endpList { - if e.ServName == servName && e.NsName == nsName { - del = append(del, ename) - } - } - - for _, ename := range del { - delete(f.endpList, ename) - f.deletedEndp = append(f.deletedEndp, ename) - } - - return nil -} - -func (f *fakeServReg) GetEndp(nsName, servName, endpName string) (*Endpoint, error) { return nil, nil } - -func (f *fakeServReg) ListEndp(nsName, servName string) ([]*Endpoint, error) { - if _, exists := f.endpList["list-error"]; exists { - return nil, errors.New("error") - } - - list := []*Endpoint{} - for _, s := range f.endpList { - if s.NsName == nsName && s.ServName == servName { - list = append(list, s) - } - } - - return list, nil -} - -func (f *fakeServReg) CreateEndp(endp *Endpoint) (*Endpoint, error) { - if endp.Name == "create-error" { - return nil, errors.New("create-endp-error") - } - - _, exists := f.endpList[endp.Name] - if exists { - return nil, ErrAlreadyExists - } - - f.endpList[endp.Name] = endp - f.createdEndp = append(f.createdEndp, endp.Name) - - return f.endpList[endp.Name], nil -} - -func (f *fakeServReg) UpdateEndp(endp *Endpoint) (*Endpoint, error) { - if endp.Name == "update-error" { - return nil, errors.New("update-endp-error") - } - - _, exists := f.endpList[endp.Name] - if !exists { - return nil, ErrNotFound - } - - f.endpList[endp.Name] = endp - f.updatedEndp = append(f.updatedEndp, endp.Name) - - return f.endpList[endp.Name], nil -} - -func (f *fakeServReg) DeleteEndp(nsName, servName, endpName string) error { - if endpName == "delete-error" { - return errors.New("delete-endp-error") - } - - _, exists := f.endpList[endpName] - if !exists { - return ErrNotFound - } - - delete(f.endpList, endpName) - f.deletedEndp = append(f.deletedEndp, endpName) - - return nil -} - -func (f *fakeServReg) ExtractData(ns *corev1.Namespace, serv *corev1.Service) (*Namespace, *Service, []*Endpoint, error) { - // No need to implement this - return nil, nil, nil, nil -} - -func TestNewBroker(t *testing.T) { - // prepare - var f *fakeServReg - assert := a.New(t) - b, err := NewBroker(nil, MetadataPair{}) - - assert.Nil(b) - assert.Equal(ErrServRegNotProvided, err) - - b, err = NewBroker(f, MetadataPair{}) - assert.NotNil(b) - assert.NoError(err) - assert.Equal(b.opMetaPair.Key, defOpKey) - assert.Equal(b.opMetaPair.Value, defOpVal) - - b, err = NewBroker(f, MetadataPair{Key: "test", Value: "testing"}) - assert.Equal(b.opMetaPair.Key, "test") - assert.Equal(b.opMetaPair.Value, "testing") -} diff --git a/pkg/servregistry/data.go b/pkg/servregistry/data.go deleted file mode 100644 index b7d41f2..0000000 --- a/pkg/servregistry/data.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servregistry - -// Namespace holds data about a namespace -type Namespace struct { - // Name of the namespace - Name string `yaml:"name" json:"name"` - // Metadata is a key-value map with metadata of the namespace - Metadata map[string]string `yaml:"metadata" json:"metadata"` -} - -// Service holds data about a service -type Service struct { - // Name of the service - Name string `yaml:"name" json:"name"` - // NsName is the name of the namespace that contains this service - NsName string `yaml:"namespaceName" json:"namespaceName"` - // Metadata is a key-value map with metadata of this service - Metadata map[string]string `yaml:"metadata" json:"metadata"` -} - -// Endpoint holds data about an endpoint -type Endpoint struct { - // Name of the endpoint - Name string `yaml:"name" json:"name"` - // ServName is the name of the service that contains this endpoint - ServName string `yaml:"serviceName" json:"serviceName"` - // NsName is the name of the namespace that contains the service this - // endpoint belongs to - NsName string `yaml:"namespaceName" json:"namespaceName"` - // Metadata is a key-value map with metadata of this endpoint - Metadata map[string]string `yaml:"metadata" json:"metadata"` - // Address, i.e. IPv4 or IPv6, of this endpoint - Address string `yaml:"address" json:"address"` - // Port of this endpoint - Port int32 `yaml:"port" json:"port"` -} diff --git a/pkg/servregistry/doc.go b/pkg/servregistry/doc.go deleted file mode 100644 index 08e6a22..0000000 --- a/pkg/servregistry/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -// Package servregistry holds code and types that are useful/implemented -// by service registries. -package servregistry diff --git a/pkg/servregistry/endpoint.go b/pkg/servregistry/endpoint.go deleted file mode 100644 index e1cf482..0000000 --- a/pkg/servregistry/endpoint.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servregistry - -// This file contains functions that perform operations on endpoints, -// such as create/update/delete. -// These functions belong to a ServiceRegistryBroker, defined in -// broker.go - -// ManageServEndps updates the endpoints of the provided service -// with the provided endpoints. Additionally, it removes endpoints from the -// service registry if they have been removed from the Kubernetes service. -// The first returned value is a key-value map where the key is the name of the -// endpoint and value the error occurred in case the endpoint failed to -// update/delete. -// The second error value is only returned if the function could not perform -// any operation at all, such as when some data is invalid or it could not -// load the endpoints from the service registry. -// -// NOTE: if the array is empty, then *all* the endpoints will be removed from -// the service registry, apart from those not owned by the cnwan operator. -// NOTE: NsName and ServName in endpsData will be ignored by the function, -// as only the first two arguments will be considered. -// This is because endpoints must all belong to the same service. -// -// For example: updates the metadata, address and/or of the endpoints. -func (b *Broker) ManageServEndps(nsName, servName string, endpsData []*Endpoint) (endpErrs map[string]error, err error) { - // endpsData: data of the endpoints in Kubernetes (latest update) - // regEndps: data of the endpoints currently in the service registry - - if b.Reg == nil { - return nil, ErrServRegNotProvided - } - - // -- Validate - if len(nsName) == 0 { - return nil, ErrNsNameNotProvided - } - - if len(servName) == 0 { - return nil, ErrServNameNotProvided - } - - // -- Init - b.lock.Lock() - defer b.lock.Unlock() - l := b.log.WithName("ManageServEndps").WithValues("serv-name", servName, "ns-name", nsName) - - // -- Do stuff - l.V(1).Info("going to update endpoints in service registry") - - endpsMap := map[string]*Endpoint{} - for _, endp := range endpsData { - endpsMap[endp.Name] = endp - if endpsMap[endp.Name].Metadata == nil { - endpsMap[endp.Name].Metadata = map[string]string{} - } - endpsMap[endp.Name].Metadata[b.opMetaPair.Key] = b.opMetaPair.Value - } - endpErrs = map[string]error{} - - // Check what changed - var listRegEndps []*Endpoint - listRegEndps, err = b.Reg.ListEndp(nsName, servName) - if err != nil { - return - } - - for _, regEndp := range listRegEndps { - // endpData: the endpoint as it is in Kubernetes - // regEndp: the endpoint as it is registered in the service registry - - l := l.WithValues("endp-name", regEndp.Name) - - endpData, exists := endpsMap[regEndp.Name] - - if owner, ownerExists := regEndp.Metadata[b.opMetaPair.Key]; owner != b.opMetaPair.Value || !ownerExists { - l.V(0).Info("endpoint is not managed by the cnwan operator and is going to be ignored") - endpErrs[regEndp.Name] = ErrEndpNotOwnedByOp - delete(endpsMap, regEndp.Name) - continue - } - - if !exists { - l.V(1).Info("going to delete endpoint from service registry") - - // This endpoint is not in the k8s service. - // We gotta delete this from the service registry. - delErr := b.Reg.DeleteEndp(nsName, servName, regEndp.Name) - - if delErr != nil { - l.Error(delErr, "error while deleting endpoint from service registry") - endpErrs[regEndp.Name] = delErr - } else { - l.V(0).Info("endpoint deleted from service registry") - } - - continue - } - - // This endpoint exists in the k8s service as well. - // We gotta check if the k8s one is different. - if endpData.Address != regEndp.Address || endpData.Port != regEndp.Port || - !b.deepEqualMetadata(endpData.Metadata, regEndp.Metadata) { - _, updErr := b.Reg.UpdateEndp(endpData) - - if updErr != nil { - l.Error(updErr, "error while updating endpoint in service registry") - endpErrs[regEndp.Name] = updErr - - } else { - l.V(0).Info("endpoint updated in service registry") - } - } - - // Remove it from the map, so we don't create this later - delete(endpsMap, regEndp.Name) - } - - // Create the new ones - for _, endpData := range endpsMap { - l := l.WithValues("endp-name", endpData.Name) - - _, createErr := b.Reg.CreateEndp(endpData) - if createErr != nil { - l.Error(createErr, "error while creating endpoint in service registry") - endpErrs[endpData.Name] = createErr - continue - } - - l.V(0).Info("endpoint created in service registry") - } - - return -} diff --git a/pkg/servregistry/endpoint_test.go b/pkg/servregistry/endpoint_test.go deleted file mode 100644 index ca4f71b..0000000 --- a/pkg/servregistry/endpoint_test.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servregistry - -import ( - "testing" - - a "github.com/stretchr/testify/assert" -) - -func TestManageServEndps(t *testing.T) { - // prepare - nsName, servName := "ns", "serv" - var f *fakeServReg - b, _ := NewBroker(f, MetadataPair{}) - - resetFake := func() { - f = newFakeStruct() - b.Reg = f - } - - resetFake() - - // Test validation - testValidation := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - // no service registry provided - b.Reg = nil - regEndps, err := b.ManageServEndps(nsName, servName, nil) - assert.Empty(regEndps) - assert.Equal(ErrServRegNotProvided, err) - - // ns name is not specified - b.Reg = f - regEndps, err = b.ManageServEndps("", servName, nil) - assert.Empty(regEndps) - assert.Equal(ErrNsNameNotProvided, err) - - // serv name is not specified - regEndps, err = b.ManageServEndps(nsName, "", nil) - assert.Empty(regEndps) - assert.Equal(ErrServNameNotProvided, err) - - // error while getting list of endpoints - f.endpList = map[string]*Endpoint{"list-error": {}} - regEndps, err = b.ManageServEndps(nsName, servName, []*Endpoint{}) - assert.Empty(regEndps) - assert.Error(err) - - assert.Empty(f.createdEndp) - assert.Empty(f.updatedEndp) - assert.Empty(f.deletedEndp) - } - - // Test endpoints not owned by the operator are not modified - testNotOwned := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - oneNotOwned := &Endpoint{Name: "one", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}} - twoNotOwned := &Endpoint{Name: "two", NsName: nsName, ServName: servName, Metadata: map[string]string{"key": "val"}} - oneChange := &Endpoint{Name: "one", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - twoChange := &Endpoint{Name: "two", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - f.endpList[oneNotOwned.Name] = oneNotOwned - f.endpList[twoNotOwned.Name] = twoNotOwned - - endpErrs, err := b.ManageServEndps(nsName, servName, []*Endpoint{oneChange, twoChange}) - assert.NoError(err) - assert.Len(endpErrs, 2) - assert.Equal(ErrEndpNotOwnedByOp, endpErrs[oneNotOwned.Name]) - assert.Equal(ErrEndpNotOwnedByOp, endpErrs[twoNotOwned.Name]) - - assert.Empty(f.createdEndp) - assert.Empty(f.updatedEndp) - assert.Empty(f.deletedEndp) - } - - // Test endpoints owned by the operator are deleted - testOwnedDelete := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - // an error occurs while deleting one of them - oneOwned := &Endpoint{Name: "one-owned", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - errored := &Endpoint{Name: "delete-error", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - f.endpList[oneOwned.Name] = oneOwned - f.endpList[errored.Name] = errored - - endpErrs, err := b.ManageServEndps(nsName, servName, []*Endpoint{}) - assert.NoError(err) - assert.Len(endpErrs, 1) - // assert that the error was indeed thrown by DeleteEndp and not by someone else - assert.EqualError(f.DeleteEndp(nsName, servName, "delete-error"), endpErrs[errored.Name].Error()) - - assert.Len(f.deletedEndp, 1) - assert.Equal(f.deletedEndp[0], oneOwned.Name) - assert.Empty(f.createdEndp) - assert.Empty(f.updatedEndp) - } - - // Test owned endpoints are updated - testOwnedUpd := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - // an error occurs while updating one of them - no := &Endpoint{Name: "no", NsName: nsName, ServName: servName, Address: "1.1.1.1", Port: 1010, - Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, - } - metad := &Endpoint{Name: "metad", NsName: nsName, ServName: servName, Address: "10.10.10.10", Port: 8080, - Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, - } - adr := &Endpoint{Name: "adr", NsName: nsName, ServName: servName, Address: "11.11.11.11", Port: 8181, - Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, - } - por := &Endpoint{Name: "por", NsName: nsName, ServName: servName, Address: "12.12.12.12", Port: 8282, - Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, - } - metadChange := &Endpoint{Name: "metad", NsName: nsName, ServName: servName, Address: "10.10.10.10", Port: 8080, - Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}, - } - adrChange := &Endpoint{Name: "adr", NsName: nsName, ServName: servName, Address: "12.12.12.12", Port: 8181, - Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, - } - porChange := &Endpoint{Name: "por", NsName: nsName, ServName: servName, Address: "12.12.12.12", Port: 2828, - Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, - } - errored := &Endpoint{Name: "update-error", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - erroredChange := &Endpoint{Name: "update-error", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} - - f.endpList[no.Name] = no - f.endpList[metad.Name] = metad - f.endpList[adr.Name] = adr - f.endpList[por.Name] = por - f.endpList[errored.Name] = errored - - endpErrs, err := b.ManageServEndps(nsName, servName, []*Endpoint{metadChange, adrChange, porChange, erroredChange, no}) - assert.NoError(err) - assert.Len(endpErrs, 1) - _, expErr := f.UpdateEndp(&Endpoint{Name: "update-error"}) - assert.EqualError(expErr, endpErrs[errored.Name].Error()) - - // check that the function was actually called for each change - assert.Contains(f.updatedEndp, metad.Name) - assert.Contains(f.updatedEndp, adr.Name) - assert.Contains(f.updatedEndp, por.Name) - assert.NotContains(f.updatedEndp, no.Name) - - // assert that nothing was created or deleted - assert.Empty(f.createdEndp) - assert.Empty(f.deletedEndp) - } - - // Test endpoints are created correctly - testOwnedCreate := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - // an error occurs while creating one of them - createNil := &Endpoint{Name: "createNil", NsName: nsName, ServName: servName, Address: "1.1.1.1", Port: 1010} - create := &Endpoint{Name: "create", NsName: nsName, ServName: servName, Address: "1.1.1.1", Port: 1010, - Metadata: map[string]string{"key": "val"}, - } - createErr := &Endpoint{Name: "create-error", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - exists := &Endpoint{Name: "exists", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - del := &Endpoint{Name: "del", NsName: nsName, ServName: servName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - f.endpList[exists.Name] = exists - f.endpList[del.Name] = del - - endpErrs, err := b.ManageServEndps(nsName, servName, []*Endpoint{create, createNil, createErr, exists}) - assert.NoError(err) - assert.Len(endpErrs, 1) - _, expErr := f.CreateEndp(&Endpoint{Name: "create-error"}) - assert.EqualError(expErr, endpErrs[createErr.Name].Error()) - - // check that the function was actually called - assert.Len(f.createdEndp, 2) - assert.Contains(f.createdEndp, create.Name) - assert.Contains(f.createdEndp, createNil.Name) - assert.Equal(create.Name, f.endpList[create.Name].Name) - assert.Equal(create.ServName, f.endpList[create.Name].ServName) - assert.Equal(map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, f.endpList[create.Name].Metadata) - assert.Equal(createNil.Name, f.endpList[createNil.Name].Name) - assert.Equal(createNil.ServName, f.endpList[createNil.Name].ServName) - assert.Equal(map[string]string{b.opMetaPair.Key: b.opMetaPair.Value}, f.endpList[createNil.Name].Metadata) - assert.Equal(create.NsName, f.endpList[create.Name].NsName) - - // assert that nothing was updated - assert.Empty(f.updatedEndp) - // assert that no one apart from del was deleted - assert.Len(f.deletedEndp, 1) - assert.Equal(f.deletedEndp[0], del.Name) - } - - testValidation(t) - testNotOwned(t) - testOwnedDelete(t) - testOwnedUpd(t) - testOwnedCreate(t) -} diff --git a/pkg/servregistry/errors.go b/pkg/servregistry/errors.go deleted file mode 100644 index 22200f1..0000000 --- a/pkg/servregistry/errors.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servregistry - -import "errors" - -var ( - // ErrServRegNotProvided is returned when the broker has no service - // registry and, thus, cannot make any changes - ErrServRegNotProvided error = errors.New("no service registry is provided") - // ErrNotFound is returned when the resource does not exist - ErrNotFound error = errors.New("resource not found") - // ErrAlreadyExists is returned when the resource already exists - ErrAlreadyExists error = errors.New("resource already exists") - // ErrServNotProvided is returned when the service is missing, i.e. is nil - ErrServNotProvided error = errors.New("service is empty") - // ErrServNoMetadata is returned when the provided service has no metadata - ErrServNoMetadata error = errors.New("service has no metadata") - // ErrNsNotProvided is returned when the namespace is missing, i.e. is nil - ErrNsNotProvided error = errors.New("namespace is empty") - // ErrServNameNotProvided is returned when the service name is empty - ErrServNameNotProvided error = errors.New("service name is empty") - // ErrNsNameNotProvided is returned when the namespace name is empty - ErrNsNameNotProvided error = errors.New("namespace name is empty") - // ErrNoEndpoints is returned when a service has no endpoints - ErrNoEndpoints error = errors.New("service has no endpoints") - // ErrNsNotEmpty is returned when trying to delete a namespace that is not - // empty - ErrNsNotEmpty error = errors.New("namespace is not empty") - // ErrServNotEmpty is returned when trying to delete a service that is not - // empty - ErrServNotEmpty error = errors.New("service is not empty") - // ErrNsNotOwnedServs is returned when trying to delete a namespace that - // has services that are not owned by the operator - ErrNsNotOwnedServs error = errors.New("namespace contains services not owned by the operator") - // ErrServNotOwnedEndps is returned when trying to delete a service that - // has endpoints that are not owned by the operator - ErrServNotOwnedEndps error = errors.New("service contains endpoints not owned by the operator") - // ErrNsNotOwnedByOp is returned when a namespace is not owned by the - // cnwan operator and therefore the action cannot be performed - ErrNsNotOwnedByOp error = errors.New("namespace is not owned by the cnwan operator") - // ErrServNotOwnedByOp is returned when a service is not owned by the - // cnwan operator and therefore the action cannot be performed - ErrServNotOwnedByOp error = errors.New("service is not owned by the cnwan operator") - // ErrEndpNotOwnedByOp is returned when an endpoint is not owned by the - // cnwan operator and therefore the action cannot be performed - ErrEndpNotOwnedByOp error = errors.New("endpoint is not owned by the cnwan operator") - // ErrTimeOutExpired is returned when the timeout of a context is expired - ErrTimeOutExpired error = errors.New("timeout expired while waiting for service registry to reply") - // ErrEndpNameNotProvided is returned when the endpoint name is empty - ErrEndpNameNotProvided error = errors.New("endpoint name not provided") - // ErrEndpNotProvided is returned when the endpoint is missing, i.e. is nil - ErrEndpNotProvided error = errors.New("endpoint is empty") -) diff --git a/pkg/servregistry/etcd/doc.go b/pkg/servregistry/etcd/doc.go deleted file mode 100644 index 30cdf94..0000000 --- a/pkg/servregistry/etcd/doc.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -// Package etcd connects to an etcd cluster to perform service registry -// operations. -// -// Read this documentation at -// https://pkg.go.dev/github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry/etcd -// -// Etcd as a service registry -// -// etcd is a distributed and reliable key-value store, and while it is -// oblivious of the data you store there, it makes sense to use it as a Service -// Registry: for example, coreDNS can use etcd as a backend where to retrieve -// records from before answering to DNS queries. -// -// Each object inserted to etcd will have a key which identifies it in some way -// and a value with all data that are relevant to the specific object. -// -// To learn more about etcd, see https://etcd.io/. -// -// To learn more about the objects mentioned above you can visit CN-WAN's -// servregistry package -// (https://pkg.go.dev/github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry) -// for the technical documentation or CN-WAN Operator's official documentation -// (https://github.com/CloudNativeSDWAN/cnwan-operator). -// -// Values -// -// Values are the service registry objects and can be one of the following: -// -// - Namespace, -// -// - Service, -// -// - or Endpoint. -// -// Please visit the links above to learn how those -// objects are implemented in go and their use/meaning, respectively. -// -// Keys -// -// Being a flat key-value store, there is no real concept of hierarchy. -// -// Thus, given that the objects defined above do need such structure, this will be -// emulated with the well-known use of prefixes, which will make the key -// resemble a path, for example: -// /prefix-1/object-1-name/prefix-2/object-2-name -// -// These are the keys that are used by this package: -// -// - namespaces will have keys in the format of -// namespaces/ -// -// for example: -// namespaces/my-project -// -// - services will have keys in the format of -// namespaces/namespace-name/services/service-name -// for example: -// namespaces/my-project/services/user-profile -// -// - endpoints will have keys in the format of -// namespaces/namespace-name/services/service-name/endpoints/endpoint-name -// for example: -// namespaces/my-project/services/user-profile/endpoints/user-profile-1 -// -// Default global prefix -// -// A sort of "global" prefix can be used: something that specifies that all -// keys that begin with this prefix belong to the service registry. This is -// useful in case you are already using etcd for other purposes or plan to do -// so. -// -// Unless an explicit prefix is passed, this package will use the default one: -// /service-registry/ -// For example, a namespace key will be: -// /service-registry/namespaces/prod -// -// Transactions -// -// Insertions, updates and deletions are all performed in transactions. -// -// Usage -// -// Read the single functions documentation and the example to learn how to use -// this package. -package etcd diff --git a/pkg/servregistry/etcd/endpoint.go b/pkg/servregistry/etcd/endpoint.go deleted file mode 100644 index 356d1bb..0000000 --- a/pkg/servregistry/etcd/endpoint.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "context" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "gopkg.in/yaml.v3" -) - -// GetEndp returns the endpoint, if it exists. -// -// Read the documentation for this method on servregistry's package. -func (e *EtcdServReg) GetEndp(nsName, servName, endpName string) (*sr.Endpoint, error) { - key, err := KeyFromServiceRegistryObject(&sr.Endpoint{ - NsName: nsName, ServName: servName, Name: endpName, - }) - if err != nil { - return nil, err - } - - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - endp, err := e.getOne(ctx, key) - if err != nil { - return nil, err - } - - return endp.(*sr.Endpoint), nil -} - -// ListServ returns a list of services inside the provided namespace. -// -// Read the documentation for this method on servregistry's package. -func (e *EtcdServReg) ListEndp(nsName, servName string) (endpList []*sr.Endpoint, err error) { - key, keyErr := KeyFromServiceRegistryObject(&sr.Service{NsName: nsName, Name: servName}) - if keyErr != nil { - return nil, keyErr - } - - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - err = e.getList(ctx, key, func(item []byte) { - var endp *sr.Endpoint - if err := yaml.Unmarshal(item, &endp); err == nil { - endpList = append(endpList, endp) - return - } - }) - - if err != nil { - return nil, err - } - - return -} - -// CreateEndp creates the endpoint. -// -// Read the documentation for this method on servregistry's package. -func (e *EtcdServReg) CreateEndp(endp *sr.Endpoint) (*sr.Endpoint, error) { - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - if err := e.put(ctx, endp, false); err != nil { - return nil, err - } - - return endp, nil -} - -// UpdateEndp updates the endpoint. -func (e *EtcdServReg) UpdateEndp(endp *sr.Endpoint) (*sr.Endpoint, error) { - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - if err := e.put(ctx, endp, true); err != nil { - return nil, err - } - - return endp, nil -} - -// DeleteEndp deletes the endpoint. -// -// Read the documentation for this method on servregistry's package. -func (e *EtcdServReg) DeleteEndp(nsName, servName, endpName string) error { - key, err := KeyFromServiceRegistryObject(&sr.Endpoint{ - NsName: nsName, ServName: servName, Name: endpName, - }) - if err != nil { - return err - } - - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - return e.delete(ctx, key) -} diff --git a/pkg/servregistry/etcd/endpoint_test.go b/pkg/servregistry/etcd/endpoint_test.go deleted file mode 100644 index 5686005..0000000 --- a/pkg/servregistry/etcd/endpoint_test.go +++ /dev/null @@ -1,534 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "context" - "fmt" - "testing" - - "go.etcd.io/etcd/api/v3/etcdserverpb" - "go.etcd.io/etcd/api/v3/mvccpb" - clientv3 "go.etcd.io/etcd/client/v3" - "gopkg.in/yaml.v3" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/stretchr/testify/assert" -) - -func TestGetEndp(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{ - mainCtx: context.Background(), - } - unknownErr := fmt.Errorf("unknwon") - endp := &sr.Endpoint{ - NsName: "namespace-name", - ServName: "service-name", - Name: "endpoint-name", - Metadata: map[string]string{"protocol": "tcp"}, - } - endpBytes, _ := yaml.Marshal(endp) - cases := []struct { - get func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) - nsName string - servName string - name string - expRes *sr.Endpoint - expErr error - }{ - { - expErr: sr.ErrNsNameNotProvided, - }, - { - nsName: endp.NsName, - expErr: sr.ErrServNameNotProvided, - }, - { - nsName: endp.NsName, - servName: endp.ServName, - expErr: sr.ErrEndpNameNotProvided, - }, - { - nsName: endp.NsName, - servName: endp.ServName, - name: endp.Name, - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - // errors are already tested in getOne - return nil, fmt.Errorf("any error") - }, - expErr: unknownErr, - }, - { - nsName: endp.NsName, - servName: endp.ServName, - name: endp.Name, - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - { - Value: endpBytes, - }, - }, - }, nil - }, - expRes: endp, - }, - } - - for i, currCase := range cases { - f := &fakeKV{ - _get: currCase.get, - } - e.kv = f - - var errErr bool - res, err := e.GetEndp(currCase.nsName, currCase.servName, currCase.name) - errRes := a.Equal(currCase.expRes, res) - - if currCase.expErr == unknownErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestListEndp(t *testing.T) { - a := assert.New(t) - unknErr := fmt.Errorf("unknown") - e := &EtcdServReg{mainCtx: context.Background()} - endp := &sr.Endpoint{ - NsName: "namespace-name", - ServName: "service-name", - Name: "endpoint-name", - Metadata: map[string]string{ - "protocol": "tcp", - }, - } - endp2 := &sr.Endpoint{ - NsName: "namespace-name", - ServName: "service-name", - Name: "endpoint-name-2", - Metadata: map[string]string{ - "protocol": "udp", - }, - } - endpBytes, _ := yaml.Marshal(endp) - endpBytes2, _ := yaml.Marshal(endp2) - invalid := []byte(`name: invalid - name: invalid2`) - - cases := []struct { - id string - nsName string - servName string - get func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) - expRes []*sr.Endpoint - expErr error - }{ - { - id: "empty-ns-name", - expErr: sr.ErrNsNameNotProvided, - }, - { - id: "empty-ns-name", - nsName: endp.NsName, - expErr: sr.ErrServNameNotProvided, - }, - { - id: "any-error", // all the specific errors are tested in TestGetList - nsName: endp.NsName, - servName: endp.ServName, - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return nil, fmt.Errorf("any error") - }, - expErr: unknErr, - }, - { - id: "should-marshal-some", // Other test cases are done in TestGetList - nsName: endp.NsName, - servName: endp.ServName, - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - {Key: []byte(KeyFromNames(endp.NsName, endp.ServName, endp.Name).String()), Value: endpBytes}, - {Key: []byte(KeyFromNames(endp2.NsName, endp2.ServName, endp2.Name).String()), Value: endpBytes2}, - {Key: []byte(KeyFromNames("whatever", "whatever", "invalid").String()), Value: invalid}, - }, - }, nil - }, - expRes: []*sr.Endpoint{endp, endp2}, - }, - } - - for _, currCase := range cases { - e.kv = &fakeKV{ - _get: currCase.get, - } - - var errErr bool - res, err := e.ListEndp(currCase.nsName, currCase.servName) - - errRes := a.Equal(currCase.expRes, res) - if currCase.expErr == unknErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %s failed", currCase.id)) - } - } -} - -func TestCreateEndp(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{ - mainCtx: context.Background(), - } - unknownErr := fmt.Errorf("unknwon") - endp := &sr.Endpoint{ - NsName: "namespace-name", - ServName: "service-name", - Name: "endpoint-name", - Metadata: map[string]string{"protocol": "tcp"}, - } - txn := &fakeTXN{} - txn._if = func(cs ...clientv3.Cmp) clientv3.Txn { - return txn - } - txn._then = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - txn._else = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - - cases := []struct { - endp *sr.Endpoint - commit func() (*clientv3.TxnResponse, error) - expRes *sr.Endpoint - expErr error - }{ - { - endp: endp, - commit: func() (*clientv3.TxnResponse, error) { - // All other errors are tested in testPut - return nil, fmt.Errorf("any error") - }, - expErr: unknownErr, - }, - { - endp: endp, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: true, - }, nil - }, - expRes: endp, - }, - { - endp: endp, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - }, nil - }, - expErr: sr.ErrAlreadyExists, - }, - { - endp: endp, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - Responses: []*etcdserverpb.ResponseOp{ - { - Response: &etcdserverpb.ResponseOp_ResponseRange{ - ResponseRange: &etcdserverpb.RangeResponse{ - Count: 0, - }, - }, - }, - }, - }, nil - }, - expErr: fmt.Errorf("namespace with name %s does not exist", endp.NsName), - }, - { - endp: endp, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - Responses: []*etcdserverpb.ResponseOp{ - { - Response: &etcdserverpb.ResponseOp_ResponseRange{ - ResponseRange: &etcdserverpb.RangeResponse{ - Count: 1, - }, - }, - }, - { - Response: &etcdserverpb.ResponseOp_ResponseRange{ - ResponseRange: &etcdserverpb.RangeResponse{ - Count: 0, - }, - }, - }, - }, - }, nil - }, - expErr: fmt.Errorf("service with name %s does not exist", endp.ServName), - }, - } - - for i, currCase := range cases { - f := &fakeKV{} - f._txn = func(ctx context.Context) clientv3.Txn { - return txn - } - txn._commit = currCase.commit - e.kv = f - - var errErr bool - res, err := e.CreateEndp(currCase.endp) - errRes := a.Equal(currCase.expRes, res) - - if currCase.expErr == unknownErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestUpdateEndp(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{ - mainCtx: context.Background(), - } - unknownErr := fmt.Errorf("unknwon") - endp := &sr.Endpoint{ - NsName: "namespace-name", - ServName: "service-name", - Name: "endpoint-name", - Metadata: map[string]string{"protocol": "tcp"}, - } - txn := &fakeTXN{} - txn._if = func(cs ...clientv3.Cmp) clientv3.Txn { - return txn - } - txn._then = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - txn._else = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - - cases := []struct { - endp *sr.Endpoint - commit func() (*clientv3.TxnResponse, error) - expRes *sr.Endpoint - expErr error - }{ - { - endp: endp, - commit: func() (*clientv3.TxnResponse, error) { - // All other errors are tested in testPut - return nil, fmt.Errorf("any error") - }, - expErr: unknownErr, - }, - { - endp: endp, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: true, - }, nil - }, - expRes: endp, - }, - { - endp: endp, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - }, nil - }, - expErr: sr.ErrNotFound, - }, - { - endp: endp, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - Responses: []*etcdserverpb.ResponseOp{ - { - Response: &etcdserverpb.ResponseOp_ResponseRange{ - ResponseRange: &etcdserverpb.RangeResponse{ - Count: 0, - }, - }, - }, - }, - }, nil - }, - expErr: fmt.Errorf("namespace with name %s does not exist", endp.NsName), - }, - { - endp: endp, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - Responses: []*etcdserverpb.ResponseOp{ - { - Response: &etcdserverpb.ResponseOp_ResponseRange{ - ResponseRange: &etcdserverpb.RangeResponse{ - Count: 1, - }, - }, - }, - { - Response: &etcdserverpb.ResponseOp_ResponseRange{ - ResponseRange: &etcdserverpb.RangeResponse{ - Count: 0, - }, - }, - }, - }, - }, nil - }, - expErr: fmt.Errorf("service with name %s does not exist", endp.ServName), - }, - } - - for i, currCase := range cases { - f := &fakeKV{} - f._txn = func(ctx context.Context) clientv3.Txn { - return txn - } - txn._commit = currCase.commit - e.kv = f - - var errErr bool - res, err := e.UpdateEndp(currCase.endp) - errRes := a.Equal(currCase.expRes, res) - - if currCase.expErr == unknownErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestDeleteEndp(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{ - mainCtx: context.Background(), - } - txn := &fakeTXN{} - txn._if = func(cs ...clientv3.Cmp) clientv3.Txn { - return txn - } - txn._then = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - unknErr := fmt.Errorf("unknown") - - cases := []struct { - id string - nsName string - servName string - endpName string - commit func() (*clientv3.TxnResponse, error) - expErr error - }{ - { - id: "empty-ns-name", - expErr: sr.ErrNsNameNotProvided, - }, - { - id: "empty-serv-name", - nsName: "ns-name", - expErr: sr.ErrServNameNotProvided, - }, - { - id: "empty-endp-name", - nsName: "ns-name", - servName: "serv-name", - expErr: sr.ErrEndpNameNotProvided, - }, - { - id: "returns-any-error", // specific errors are tested in TestDelete - nsName: "ns-name", - servName: "serv-name", - endpName: "endp-name", - commit: func() (*clientv3.TxnResponse, error) { - return nil, fmt.Errorf("any error") - }, - expErr: unknErr, - }, - { - id: "is-successful", - nsName: "ns-name", - servName: "serv-name", - endpName: "endp-name", - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: true, - }, nil - }, - }, - } - - for _, currCase := range cases { - f := &fakeKV{} - f._txn = func(ctx context.Context) clientv3.Txn { - return txn - } - txn._commit = currCase.commit - e.kv = f - - var errErr bool - err := e.DeleteEndp(currCase.nsName, currCase.servName, currCase.endpName) - if currCase.expErr == unknErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errErr { - a.FailNow(fmt.Sprintf("case %s failed", currCase.id)) - } - } -} diff --git a/pkg/servregistry/etcd/errors.go b/pkg/servregistry/etcd/errors.go deleted file mode 100644 index 58fdcf4..0000000 --- a/pkg/servregistry/etcd/errors.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import "errors" - -// These errors are thrown by the package when an incorrect value is provided -// to some of its functions, or when something unexpected happens. -var ( - // ErrNilObject is returned when a function is provided with a nil - // object. - ErrNilObject error = errors.New("no object provided") - // ErrUnknownObject is returned when the KeyBuilder is provided with an - // object that is not a namespace, service or endpoint. - ErrUnknownObject error = errors.New("object is unknown") -) diff --git a/pkg/servregistry/etcd/example_key_test.go b/pkg/servregistry/etcd/example_key_test.go deleted file mode 100644 index 09fc376..0000000 --- a/pkg/servregistry/etcd/example_key_test.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "context" - "fmt" - "os" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - clientv3 "go.etcd.io/etcd/client/v3" - namespace "go.etcd.io/etcd/client/v3/namespace" -) - -// This example shows how to use the Keybuilder without any names yet. -// It is useful in case you want to build a key based on some conditions. -// -// In this very simple example, an environment variable is set to drive -// the conditions on how the key should be built. -func ExampleKeyBuilder() { - namespaceName := "ns-name" - serviceName := "serv-name" - endpName := "endp-name" - builder := &KeyBuilder{} - - os.Setenv("GET", "endpoint") - builder.SetNamespace(namespaceName).SetService(serviceName) - - if os.Getenv("GET") == "endpoint" { - builder.SetEndpoint(endpName) - } - fmt.Println(builder) - // Output: namespaces/ns-name/services/serv-name/endpoints/endp-name -} - -// This example shows how to use this package's KeyBuilder to build keys -// for etcd to use for operations that are not supported by this package, -// i.e. watching. -func ExampleKeyBuilder_withUnsupportedOperations() { - cli, err := clientv3.New(clientv3.Config{ - Endpoints: []string{ - "localhost:2379", - }, - }) - if err != nil { - fmt.Println("cannot establish connection to etcd:", err) - os.Exit(1) - } - - watcher := namespace.NewWatcher(cli.Watcher, "my-prefix/") - builder := &KeyBuilder{} - nsName := "namespace-name" - - ctx, canc := context.WithCancel(context.TODO()) - defer canc() - wchan := watcher.Watch(ctx, builder.SetNamespace(nsName).String()) - for { - w := <-wchan - if w.Canceled { - break - } - } -} - -// This example shows how to build a key starting from a list of names. -func ExampleKeyFromNames() { - namespaceName := "ns-name" - serviceName := "serv-name" - - key := KeyFromNames(namespaceName, serviceName) - fmt.Println(key) - // Output: namespaces/ns-name/services/serv-name -} - -func ExampleKeyFromString_validKey() { - key := "namespaces/ns-name/services/service-name/endpoints/endpoint-name" - - fmt.Println(KeyFromString(key).IsValid()) - // Output: true -} - -func ExampleKeyFromString_validKeyWithPrefix() { - key := "/my/prefix/is/long/namespaces/ns-name/services/service-name/endpoints/endpoint-name" - - fmt.Println(KeyFromString(key).IsValid()) - // Output: true -} - -func ExampleKeyFromString_invalidKey() { - key := "/objects/users/user-name" - - fmt.Println(KeyFromString(key).IsValid()) - // Output: false -} - -func ExampleKeyFromServiceRegistryObject_validObject() { - ns := &sr.Namespace{ - Name: "namespace-name", - Metadata: map[string]string{ - "env": "beta", - }, - } - - key, err := KeyFromServiceRegistryObject(ns) - if err != nil { - // Handle the error... - } - - fmt.Println(key.String()) - // Output: namespaces/namespace-name -} - -func ExampleKeyFromServiceRegistryObject_invalidObject() { - ns := &sr.Service{ - // A service must belong to a namespace. - // We comment this to make it an invalid object. - // NsName : "namespace-name" - Name: "service-name", - Metadata: map[string]string{ - "version": "v0.2.1", - "commit-hash": "aqvkepsclg", - }, - } - - key, err := KeyFromServiceRegistryObject(ns) - if err != nil { - fmt.Println("error:", err) - return - } - - fmt.Println(key.String()) - // Output: error: namespace name is empty -} diff --git a/pkg/servregistry/etcd/example_test.go b/pkg/servregistry/etcd/example_test.go deleted file mode 100644 index 3ad3a2a..0000000 --- a/pkg/servregistry/etcd/example_test.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "context" - "fmt" - "os" - - clientv3 "go.etcd.io/etcd/client/v3" -) - -// This example shows how to start the etcd service registry -// without a custom global prefix. This means that default one will be used -// (/service-registry/) -func ExampleNewServiceRegistryWithEtcd() { - clientConfig := clientv3.Config{ - Endpoints: []string{ - "10.11.12.13:2379", - }, - } - - cli, err := clientv3.New(clientConfig) - if err != nil { - fmt.Println("cannot establish connection to etcd:", err) - os.Exit(1) - } - - mainCtx, canc := context.WithCancel(context.Background()) - - // NewServiceRegistryWithEtcd returns an error only when the client is - // nil: this is not our case and that's why we do not check the error - // here. - servreg := NewServiceRegistryWithEtcd(mainCtx, cli, nil) - - // Do something with the service registry... - _ = servreg - - // Do other stuf... - - // Cancel the context - canc() -} - -// This example shows how to start the etcd service registry -// with a custom global prefix. As it is shown, you can even use -// multiple slashes. -func ExampleNewServiceRegistryWithEtcd_withPrefix() { - clientConfig := clientv3.Config{ - Endpoints: []string{ - "10.11.12.13:2379", - }, - } - prefix := "/app-1/service-registry/" - - cli, err := clientv3.New(clientConfig) - if err != nil { - fmt.Println("cannot establish connection to etcd:", err) - os.Exit(1) - } - - mainCtx, canc := context.WithCancel(context.Background()) - - // NewServiceRegistryWithEtcd returns an error only when the client is - // nil: this is not our case and that's why we do not check the error - // here. - servreg := NewServiceRegistryWithEtcd(mainCtx, cli, &prefix) - - // Do something with the service registry... - _ = servreg - - // Do other stuf... - - // Cancel the context - canc() -} - -// This example shows how to start the etcd service registry -// with a no prefix. -// Actually, only "/" will be used in that case. -func ExampleNewServiceRegistryWithEtcd_withEmptyPrefix() { - clientConfig := clientv3.Config{ - Endpoints: []string{ - "10.11.12.13:2379", - }, - } - prefix := "" - - cli, err := clientv3.New(clientConfig) - if err != nil { - fmt.Println("cannot establish connection to etcd:", err) - os.Exit(1) - } - - mainCtx, canc := context.WithCancel(context.Background()) - - // NewServiceRegistryWithEtcd returns an error only when the client is - // nil: this is not our case and that's why we do not check the error - // here. - servreg := NewServiceRegistryWithEtcd(mainCtx, cli, &prefix) - - // Do something with the service registry... - _ = servreg - - // Do other stuf... - - // Cancel the context - canc() -} diff --git a/pkg/servregistry/etcd/fake_kv.go b/pkg/servregistry/etcd/fake_kv.go deleted file mode 100644 index 43d64fa..0000000 --- a/pkg/servregistry/etcd/fake_kv.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "context" - - clientv3 "go.etcd.io/etcd/client/v3" -) - -type fakeKV struct { - _put func(ctx context.Context, key, val string, opts ...clientv3.OpOption) (*clientv3.PutResponse, error) - _get func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) - _delete func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.DeleteResponse, error) - _compact func(ctx context.Context, rev int64, opts ...clientv3.CompactOption) (*clientv3.CompactResponse, error) - _do func(ctx context.Context, op clientv3.Op) (clientv3.OpResponse, error) - _txn func(ctx context.Context) clientv3.Txn -} - -type fakeTXN struct { - _if func(cs ...clientv3.Cmp) clientv3.Txn - _then func(ops ...clientv3.Op) clientv3.Txn - _else func(ops ...clientv3.Op) clientv3.Txn - _commit func() (*clientv3.TxnResponse, error) -} - -func (f *fakeKV) Put(ctx context.Context, key, val string, opts ...clientv3.OpOption) (*clientv3.PutResponse, error) { - return f._put(ctx, key, val, opts...) -} - -func (f *fakeKV) Get(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return f._get(ctx, key, opts...) -} - -func (f *fakeKV) Delete(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.DeleteResponse, error) { - return f._delete(ctx, key, opts...) -} - -func (f *fakeKV) Compact(ctx context.Context, rev int64, opts ...clientv3.CompactOption) (*clientv3.CompactResponse, error) { - return f._compact(ctx, rev, opts...) -} - -func (f *fakeKV) Do(ctx context.Context, op clientv3.Op) (clientv3.OpResponse, error) { - return f._do(ctx, op) -} - -func (f *fakeKV) Txn(ctx context.Context) clientv3.Txn { - return f._txn(ctx) -} - -func (f *fakeTXN) If(cs ...clientv3.Cmp) clientv3.Txn { - return f._if(cs...) -} - -func (f *fakeTXN) Then(ops ...clientv3.Op) clientv3.Txn { - return f._then(ops...) -} - -func (f *fakeTXN) Else(ops ...clientv3.Op) clientv3.Txn { - return f._else(ops...) -} - -func (f *fakeTXN) Commit() (*clientv3.TxnResponse, error) { - return f._commit() -} diff --git a/pkg/servregistry/etcd/key.go b/pkg/servregistry/etcd/key.go deleted file mode 100644 index 6c71b60..0000000 --- a/pkg/servregistry/etcd/key.go +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "path" - "strings" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" -) - -// objectPrefix is a string the precedes the actual name of the object -type objectPrefix string - -const ( - // namespacePrefix is the string the precedes the name of the namespace - namespacePrefix objectPrefix = "namespaces" - // servicePrefix is the string the precedes the name of the service - servicePrefix objectPrefix = "services" - // endpointPrefix is the string the precedes the name of the endpoint - endpointPrefix objectPrefix = "endpoints" -) - -// ObjectType identifies the type of the object we are dealing with and will -// build the key according to it, i.e. namespace, service or endpoint. -type ObjectType int - -// These constants define the object type that the key builder will deal with. -const ( - // UnknownOrInvalidObject is an object that is neither a namespace, nor a service, - // nor an endpoint and is thus not related to service registry. - UnknownOrInvalidObject ObjectType = 0 - // NamespaceObject represents a namespace. - NamespaceObject ObjectType = iota - // ServiceObject represents a service. - ServiceObject ObjectType = iota - // EndpointObject represents an endpoint. - EndpointObject ObjectType = iota -) - -// KeyBuilder manages and builds an etcd key for service registry. -// It can create the appropriate path key based on the object type it is -// dealing with or make assumptions on what the value is based on -// its key path so that you know how to unmarshal its value. -// -// Be aware that KeyBuilder will NOT include a prefix when it returns the -// key as a string, so you should either include it manually or use the -// namespace package -// (https://pkg.go.dev/go.etcd.io/etcd@v3.3.25+incompatible/clientv3/namespace). -// -// Take a look at the examples to learn more about this. -// -// -// NOTE: as written above, Key only makes **assumptions**: you need to -// check that the unmarshal operation was successful to make sure the object -// is correct. This is performed automatically by the Service Registry -// implementer, but you have to do it on your own in case you use it with -// a crude client. -type KeyBuilder struct { - nsName string - servName string - endpName string -} - -// KeyFromNames starts building a key based on the provided names. -// This method is useful in case you want build a string and already -// know the name and parents' names of the object that will be stored as -// value. -func KeyFromNames(names ...string) *KeyBuilder { - e := &KeyBuilder{} - - size := len(names) - if size == 0 || size > 3 { - return e - } - - // namespace must always be there anyway - e.nsName = names[0] - - if size >= 2 { - e.servName = names[1] - - if size == 3 { - e.endpName = names[2] - } - } - - return e -} - -// KeyFromServiceRegistryObject returns a KeyBuilder starting from a service -// registry object defined in -// https://pkg.go.dev/github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry: -// for example a namespace, service or endpoint. -// -// In case the a key couldn't be built this method either returns an error -// belonging to package mentioned above or ErrNilObject if the object is nil. -func KeyFromServiceRegistryObject(object interface{}) (*KeyBuilder, error) { - if object == nil { - return nil, ErrNilObject - } - - switch obj := object.(type) { - case *sr.Namespace: - if len(obj.Name) == 0 { - return nil, sr.ErrNsNameNotProvided - } - return KeyFromNames(obj.Name), nil - - case *sr.Service: - if len(obj.NsName) == 0 { - return nil, sr.ErrNsNameNotProvided - } - if len(obj.Name) == 0 { - return nil, sr.ErrServNameNotProvided - } - return KeyFromNames(obj.NsName, obj.Name), nil - - case *sr.Endpoint: - if len(obj.NsName) == 0 { - return nil, sr.ErrNsNameNotProvided - } - if len(obj.ServName) == 0 { - return nil, sr.ErrServNameNotProvided - } - if len(obj.Name) == 0 { - return nil, sr.ErrEndpNameNotProvided - } - return KeyFromNames(obj.NsName, obj.ServName, obj.Name), nil - - default: - return nil, ErrUnknownObject - } -} - -// KeyFromString returns a KeyBuilder starting from a string, i.e. -// /namespaces/namespace-name/services/service-name` -// or -// /something/something-name/another/another-name -// -// This is very useful in case you want to check if the key is valid for -// the service registry. -// -// Note that this WILL also strip any prefix from the key, so if you really -// need it you should either write it manually or use the -// namespace package -// (https://pkg.go.dev/go.etcd.io/etcd@v3.3.25+incompatible/clientv3/namespace) -// from etcd, which includes/excludes it automatically for each key. -// -// Take a look at the examples to learn more. -func KeyFromString(key string) *KeyBuilder { - _key := strings.Trim(key, "/") - names := strings.Split(_key, "/") - nsIndex := -1 - - for i, name := range names { - if name == string(namespacePrefix) { - nsIndex = i - break - } - } - - if nsIndex == -1 { - return KeyFromNames() - } - - names = names[nsIndex:] - length := len(names) - if length%2 != 0 || length > 6 { - // We cannot have an odd number of names and the number cannot be more - // than 6. - // It should be one of the following: - // * ["namespaces", "name"] - // * ["namespaces", "name", "services", "name"] - // * ["namespaces", "name", "services", "name", "endpoints", "name"] - return KeyFromNames() - } - - if length == 2 { - // First example above - return KeyFromNames(names[1]) - } - - if length == 4 { - // Second example above - if names[2] != string(servicePrefix) { - return KeyFromNames() - } - - return KeyFromNames(names[1], names[3]) - } - - if length == 6 && names[4] != string(endpointPrefix) { - return KeyFromNames() - } - - // Third example above - return KeyFromNames(names[1], names[3], names[5]) -} - -// Clone returns another pointer to a KeyBuilder with the same settings -// as the one you're cloning from. -// -// Since golang doesn't have a DeepCopy method, use this in case you want -// to generate other keys leaving this one intact. -func (k *KeyBuilder) Clone() *KeyBuilder { - return &KeyBuilder{ - nsName: k.nsName, - servName: k.servName, - endpName: k.endpName, - } -} - -// IsValid returns true if the key is a valid key for service registry and is -// the equivalent of doing: -// k.ObjectType() != UnknownOrInvalidObject -func (k *KeyBuilder) IsValid() bool { - return k.ObjectType() != UnknownOrInvalidObject -} - -// ObjectType returns the assumed type of the object stored as value. -func (k *KeyBuilder) ObjectType() ObjectType { - if k.nsName == "" { - // If no namespace is there, then it is always invalid - return UnknownOrInvalidObject - } - - if k.servName == "" && k.endpName == "" { - return NamespaceObject - } - - if k.servName != "" { - if k.endpName != "" { - return EndpointObject - } - - return ServiceObject - } - - return UnknownOrInvalidObject -} - -// SetNamespace sets the namespace name. -func (k *KeyBuilder) SetNamespace(name string) *KeyBuilder { - if len(name) > 0 { - k.nsName = name - } - - return k -} - -// SetService sets the service name. -func (k *KeyBuilder) SetService(name string) *KeyBuilder { - if len(name) > 0 { - k.servName = name - } - - return k -} - -// SetEndpoint sets the endpoint name. -func (k *KeyBuilder) SetEndpoint(name string) *KeyBuilder { - if len(name) > 0 { - k.endpName = name - } - - return k -} - -// GetNamespace returns the name of the namespace, if set. -func (k *KeyBuilder) GetNamespace() (name string) { - if k.IsValid() { - name = k.nsName - } - - return name -} - -// GetService returns the name of the service, if set. -func (k *KeyBuilder) GetService() (name string) { - if k.IsValid() { - name = k.servName - } - - return name -} - -// GetEndpoint returns the name of the endpoint, if set. -func (k *KeyBuilder) GetEndpoint() (name string) { - if k.IsValid() { - name = k.endpName - } - - return name -} - -// String "marshals" the key into a string. -// -// This will not print any prefix and the key will never start with a -// `/`. -// -// In case you need that, you will have to put that manually. -// -// Note: this method will return an empty string if the key is not valid, -// i.e. when no namespace is set or the key is not suitable for service -// registry usage. -// -// Make sure to call IsValid() before marshaling to string. -func (k *KeyBuilder) String() string { - if !k.IsValid() { - return "" - } - - key := []string{} - key = append(key, string(namespacePrefix), k.nsName) - - if k.ObjectType() > NamespaceObject { - key = append(key, string(servicePrefix), k.servName) - - if k.ObjectType() == EndpointObject { - key = append(key, string(endpointPrefix), k.endpName) - } - } - - return path.Join(key...) -} diff --git a/pkg/servregistry/etcd/key_test.go b/pkg/servregistry/etcd/key_test.go deleted file mode 100644 index 7c0f187..0000000 --- a/pkg/servregistry/etcd/key_test.go +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "fmt" - "testing" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/stretchr/testify/assert" -) - -func TestKeyFromNames(t *testing.T) { - a := assert.New(t) - nsName := "ns-test" - servName := "serv-test" - endpName := "endp-test" - - cases := []struct { - names []string - expRes *KeyBuilder - }{ - { - names: []string{}, - expRes: &KeyBuilder{}, - }, - { - names: []string{nsName}, - expRes: &KeyBuilder{nsName: nsName}, - }, - { - names: []string{nsName, servName}, - expRes: &KeyBuilder{nsName: nsName, servName: servName}, - }, - { - names: []string{nsName, servName, endpName}, - expRes: &KeyBuilder{nsName: nsName, servName: servName, endpName: endpName}, - }, - { - names: []string{nsName, servName, endpName, "another"}, - expRes: &KeyBuilder{}, - }, - } - - for i, currCase := range cases { - res := KeyFromNames(currCase.names...) - if !a.Equal(currCase.expRes, res) { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestKeyFromString(t *testing.T) { - a := assert.New(t) - - cases := []struct { - key string - expRes *KeyBuilder - }{ - { - key: "/namespaces/test", - expRes: &KeyBuilder{nsName: "test"}, - }, - { - key: "////namespaces/test///", - expRes: &KeyBuilder{nsName: "test"}, - }, - { - key: "namespaces/test", - expRes: &KeyBuilder{nsName: "test"}, - }, - { - key: defaultPrefix + "/namespaces/test", - expRes: &KeyBuilder{nsName: "test"}, - }, - { - key: "something/other/entirely", - expRes: &KeyBuilder{}, - }, - { - key: "namespaces/name/services", - expRes: &KeyBuilder{}, - }, - { - key: "namespaces/name/services/name/endpoints/name/seventh", - expRes: &KeyBuilder{}, - }, - { - key: "namespaces/name", - expRes: &KeyBuilder{nsName: "name"}, - }, - { - key: "namespaces/name/servicesss/name", - expRes: &KeyBuilder{}, - }, - { - key: "namespaces/name/services/name", - expRes: &KeyBuilder{nsName: "name", servName: "name"}, - }, - { - key: "namespaces/name/services/name/eeendpoints/name", - expRes: &KeyBuilder{}, - }, - { - key: "namespaces/name/services/name/endpoints/name", - expRes: &KeyBuilder{nsName: "name", servName: "name", endpName: "name"}, - }, - } - - for i, currCase := range cases { - res := KeyFromString(currCase.key) - if !a.Equal(currCase.expRes, res) { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestKeyFromObject(t *testing.T) { - a := assert.New(t) - unk := struct { - Name string - Metadata map[string]string - }{ - Name: "test", - Metadata: map[string]string{ - "type": "unknown", - }, - } - ns := &sr.Namespace{ - Name: "ns", - Metadata: map[string]string{"type": "ns"}, - } - serv := &sr.Service{ - NsName: "ns", - Name: "serv", - Metadata: map[string]string{"type": "serv"}, - } - endp := &sr.Endpoint{ - NsName: "ns", - ServName: "serv", - Name: "endp", - Metadata: map[string]string{"type": "endp"}, - } - - cases := []struct { - arg interface{} - expRes *KeyBuilder - expErr error - }{ - { - arg: nil, - expErr: ErrNilObject, - }, - { - arg: &unk, - expErr: ErrUnknownObject, - }, - { - arg: &sr.Namespace{}, - expErr: sr.ErrNsNameNotProvided, - }, - { - arg: ns, - expRes: &KeyBuilder{nsName: ns.Name}, - }, - { - arg: &sr.Service{}, - expErr: sr.ErrNsNameNotProvided, - }, - { - arg: &sr.Service{NsName: ns.Name}, - expErr: sr.ErrServNameNotProvided, - }, - { - arg: serv, - expRes: &KeyBuilder{nsName: serv.NsName, servName: serv.Name}, - }, - { - arg: &sr.Endpoint{}, - expErr: sr.ErrNsNameNotProvided, - }, - { - arg: &sr.Endpoint{NsName: endp.NsName}, - expErr: sr.ErrServNameNotProvided, - }, - { - arg: &sr.Endpoint{NsName: endp.NsName, ServName: endp.ServName}, - expErr: sr.ErrEndpNameNotProvided, - }, - { - arg: endp, - expRes: &KeyBuilder{nsName: endp.NsName, servName: endp.ServName, endpName: endp.Name}, - }, - } - - for i, currCase := range cases { - res, err := KeyFromServiceRegistryObject(currCase.arg) - errRes := a.Equal(currCase.expRes, res) - errErr := a.Equal(currCase.expErr, err) - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestClone(t *testing.T) { - a := assert.New(t) - nsName := "ns-test" - servName := "serv-test" - endpName := "endp-test" - k := KeyFromNames(nsName, servName, endpName) - c := k.Clone() - - a.Equal(k, c) -} - -func TestObjectType(t *testing.T) { - a := assert.New(t) - nsName := "ns-test" - servName := "serv-test" - endpName := "endp-test" - - cases := []struct { - arg *KeyBuilder - expRes ObjectType - }{ - { - arg: &KeyBuilder{}, - expRes: UnknownOrInvalidObject, - }, - { - arg: (&KeyBuilder{}).SetEndpoint(endpName), - expRes: UnknownOrInvalidObject, - }, - { - arg: (&KeyBuilder{}).SetService(servName), - expRes: UnknownOrInvalidObject, - }, - { - arg: (&KeyBuilder{}).SetNamespace(nsName).SetEndpoint(endpName), - expRes: UnknownOrInvalidObject, - }, - { - arg: (&KeyBuilder{}).SetNamespace(nsName), - expRes: NamespaceObject, - }, - { - arg: (&KeyBuilder{}).SetNamespace(nsName).SetService(servName), - expRes: ServiceObject, - }, - { - arg: (&KeyBuilder{}).SetNamespace(nsName).SetService(servName).SetEndpoint(endpName), - expRes: EndpointObject, - }, - } - - for i, currCase := range cases { - if !a.Equal(currCase.expRes, currCase.arg.ObjectType()) { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestString(t *testing.T) { - a := assert.New(t) - nsName := "ns-test" - servName := "serv-test" - endpName := "endp-test" - - cases := []struct { - arg *KeyBuilder - expRes string - }{ - { - arg: &KeyBuilder{}, - expRes: "", - }, - { - arg: (&KeyBuilder{}).SetEndpoint(endpName), - expRes: "", - }, - { - arg: (&KeyBuilder{}).SetService(servName), - expRes: "", - }, - { - arg: (&KeyBuilder{}).SetNamespace(nsName).SetEndpoint(endpName), - expRes: "", - }, - { - arg: (&KeyBuilder{}).SetNamespace(nsName), - expRes: fmt.Sprintf("%s/%s", namespacePrefix, nsName), - }, - { - arg: (&KeyBuilder{}).SetNamespace(nsName).SetService(servName), - expRes: fmt.Sprintf("%s/%s/%s/%s", namespacePrefix, nsName, servicePrefix, servName), - }, - { - arg: (&KeyBuilder{}).SetNamespace(nsName).SetService(servName).SetEndpoint(endpName), - expRes: fmt.Sprintf("%s/%s/%s/%s/%s/%s", namespacePrefix, nsName, servicePrefix, servName, endpointPrefix, endpName), - }, - } - - for i, currCase := range cases { - if !a.Equal(currCase.expRes, currCase.arg.String()) { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestGetNamespace(t *testing.T) { - a := assert.New(t) - k := &KeyBuilder{} - a.Empty(k.GetNamespace()) - - nsName := "ns-test" - k.nsName = nsName - a.Equal(nsName, k.GetNamespace()) - - k.nsName = nsName - k.endpName = "test" - a.Empty(k.GetNamespace()) -} - -func TestGetService(t *testing.T) { - a := assert.New(t) - k := &KeyBuilder{} - a.Empty(k.GetService()) - - servName := "serv-test" - k.servName = servName - a.Empty(k.GetService()) - - k.nsName = "ns-test" - a.Equal(servName, k.GetService()) -} - -func TestGetEndpoint(t *testing.T) { - a := assert.New(t) - k := &KeyBuilder{} - a.Empty(k.GetEndpoint()) - - endpName := "endp-test" - k.endpName = endpName - a.Empty(k.GetEndpoint()) - - k.nsName = "ns-test" - k.servName = "serv-test" - a.Equal(endpName, k.GetEndpoint()) -} diff --git a/pkg/servregistry/etcd/namespace.go b/pkg/servregistry/etcd/namespace.go deleted file mode 100644 index 22b0123..0000000 --- a/pkg/servregistry/etcd/namespace.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "context" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "gopkg.in/yaml.v3" -) - -// GetNs returns the namespace if exists. -// -// Read the documentation for this method on servregistry's package. -func (e *EtcdServReg) GetNs(name string) (*sr.Namespace, error) { - key := KeyFromNames(name) - if !key.IsValid() { - return nil, sr.ErrNsNameNotProvided - } - - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - ns, err := e.getOne(ctx, key) - if err != nil { - return nil, err - } - - return ns.(*sr.Namespace), nil -} - -// ListNs returns a list of all namespaces. -// -// Read the documentation for this method on servregistry's package. -func (e *EtcdServReg) ListNs() (nsList []*sr.Namespace, err error) { - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - err = e.getList(ctx, nil, func(item []byte) { - var ns *sr.Namespace - if err := yaml.Unmarshal(item, &ns); err == nil { - nsList = append(nsList, ns) - return - } - }) - - if err != nil { - return nil, err - } - - return -} - -// CreateNs creates the namespace. -// -// Read the documentation for this method on servregistry's package. -func (e *EtcdServReg) CreateNs(ns *sr.Namespace) (*sr.Namespace, error) { - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - if err := e.put(ctx, ns, false); err != nil { - return nil, err - } - - return ns, nil -} - -// UpdateNs updates the namespace. -// -// Read the documentation for this method on servregistry's package. -func (e *EtcdServReg) UpdateNs(ns *sr.Namespace) (*sr.Namespace, error) { - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - if err := e.put(ctx, ns, true); err != nil { - return nil, err - } - - return ns, nil -} - -// DeleteNs deletes the namespace. -// -// Read the documentation for this method on servregistry's package. -func (e *EtcdServReg) DeleteNs(name string) error { - key := KeyFromNames(name) - if !key.IsValid() { - return sr.ErrNsNameNotProvided - } - - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - return e.delete(ctx, key) -} diff --git a/pkg/servregistry/etcd/namespace_test.go b/pkg/servregistry/etcd/namespace_test.go deleted file mode 100644 index 3acc2f4..0000000 --- a/pkg/servregistry/etcd/namespace_test.go +++ /dev/null @@ -1,391 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "context" - "fmt" - "testing" - - "go.etcd.io/etcd/api/v3/mvccpb" - clientv3 "go.etcd.io/etcd/client/v3" - "gopkg.in/yaml.v3" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/stretchr/testify/assert" -) - -func TestGetNs(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{ - mainCtx: context.Background(), - } - unknownErr := fmt.Errorf("unknwon") - ns := &sr.Namespace{ - Name: "namespace-name", - Metadata: map[string]string{"env": "beta"}, - } - nsBytes, _ := yaml.Marshal(ns) - cases := []struct { - get func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) - name string - expRes *sr.Namespace - expErr error - }{ - { - name: "", - expErr: sr.ErrNsNameNotProvided, - }, - { - name: ns.Name, - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - // errors are already tested in getOne - return nil, fmt.Errorf("any error") - }, - expErr: unknownErr, - }, - { - name: ns.Name, - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - { - Value: nsBytes, - }, - }, - }, nil - }, - expRes: ns, - }, - } - - for i, currCase := range cases { - f := &fakeKV{ - _get: currCase.get, - } - e.kv = f - - var errErr bool - res, err := e.GetNs(currCase.name) - errRes := a.Equal(currCase.expRes, res) - - if currCase.expErr == unknownErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestListNs(t *testing.T) { - a := assert.New(t) - unknErr := fmt.Errorf("unknown") - e := &EtcdServReg{mainCtx: context.Background()} - ns := &sr.Namespace{ - Name: "namespace-name", - Metadata: map[string]string{ - "env": "beta", - }, - } - ns2 := &sr.Namespace{ - Name: "namespace-name-2", - Metadata: map[string]string{ - "env": "prod", - }, - } - nsBytes, _ := yaml.Marshal(ns) - nsBytes2, _ := yaml.Marshal(ns2) - invalid := []byte(`name: invalid - name: invalid2`) - - cases := []struct { - id string - get func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) - expRes []*sr.Namespace - expErr error - }{ - { - id: "any-error", // all the specific errors are tested in TestGetList - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return nil, fmt.Errorf("any error") - }, - expErr: unknErr, - }, - { - id: "should-marshal-some", // Other test cases are done in TestGetList - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - {Key: []byte(KeyFromNames(ns.Name).String()), Value: nsBytes}, - {Key: []byte(KeyFromNames(ns2.Name).String()), Value: nsBytes2}, - {Key: []byte(KeyFromNames("invalid").String()), Value: invalid}, - }, - }, nil - }, - expRes: []*sr.Namespace{ns, ns2}, - }, - } - - for _, currCase := range cases { - e.kv = &fakeKV{ - _get: currCase.get, - } - - var errErr bool - res, err := e.ListNs() - - errRes := a.Equal(currCase.expRes, res) - if currCase.expErr == unknErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %s failed", currCase.id)) - } - } -} - -func TestCreateNs(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{ - mainCtx: context.Background(), - } - unknownErr := fmt.Errorf("unknwon") - ns := &sr.Namespace{ - Name: "namespace-name", - Metadata: map[string]string{"env": "beta"}, - } - txn := &fakeTXN{} - txn._if = func(cs ...clientv3.Cmp) clientv3.Txn { - return txn - } - txn._then = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - txn._else = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - - cases := []struct { - ns *sr.Namespace - commit func() (*clientv3.TxnResponse, error) - expRes *sr.Namespace - expErr error - }{ - { - ns: ns, - commit: func() (*clientv3.TxnResponse, error) { - // All other errors are tested in testPut - return nil, fmt.Errorf("any error") - }, - expErr: unknownErr, - }, - { - ns: ns, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: true, - }, nil - }, - expRes: ns, - }, - { - ns: ns, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - }, nil - }, - expErr: sr.ErrAlreadyExists, - }, - } - - for i, currCase := range cases { - f := &fakeKV{} - f._txn = func(ctx context.Context) clientv3.Txn { - return txn - } - txn._commit = currCase.commit - e.kv = f - - var errErr bool - res, err := e.CreateNs(currCase.ns) - errRes := a.Equal(currCase.expRes, res) - - if currCase.expErr == unknownErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestUpdateNs(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{ - mainCtx: context.Background(), - } - unknownErr := fmt.Errorf("unknwon") - ns := &sr.Namespace{ - Name: "namespace-name", - Metadata: map[string]string{"env": "beta"}, - } - txn := &fakeTXN{} - txn._if = func(cs ...clientv3.Cmp) clientv3.Txn { - return txn - } - txn._then = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - txn._else = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - - cases := []struct { - ns *sr.Namespace - commit func() (*clientv3.TxnResponse, error) - expRes *sr.Namespace - expErr error - }{ - { - ns: ns, - commit: func() (*clientv3.TxnResponse, error) { - // All other errors are tested in testPut - return nil, fmt.Errorf("any error") - }, - expErr: unknownErr, - }, - { - ns: ns, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: true, - }, nil - }, - expRes: ns, - }, - { - ns: ns, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - }, nil - }, - expErr: sr.ErrNotFound, - }, - } - - for i, currCase := range cases { - f := &fakeKV{} - f._txn = func(ctx context.Context) clientv3.Txn { - return txn - } - txn._commit = currCase.commit - e.kv = f - - var errErr bool - res, err := e.UpdateNs(currCase.ns) - errRes := a.Equal(currCase.expRes, res) - - if currCase.expErr == unknownErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestDeleteNs(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{ - mainCtx: context.Background(), - } - txn := &fakeTXN{} - txn._if = func(cs ...clientv3.Cmp) clientv3.Txn { - return txn - } - txn._then = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - unknErr := fmt.Errorf("unknown") - - cases := []struct { - id string - name string - commit func() (*clientv3.TxnResponse, error) - expErr error - }{ - { - id: "empty-ns-name", - expErr: sr.ErrNsNameNotProvided, - }, - { - id: "returns-any-error", // specific errors are tested in TestDelete - name: "ns-name", - commit: func() (*clientv3.TxnResponse, error) { - return nil, fmt.Errorf("any error") - }, - expErr: unknErr, - }, - { - id: "is-successful", - name: "ns-name", - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: true, - }, nil - }, - }, - } - - for _, currCase := range cases { - f := &fakeKV{} - f._txn = func(ctx context.Context) clientv3.Txn { - return txn - } - txn._commit = currCase.commit - e.kv = f - - var errErr bool - err := e.DeleteNs(currCase.name) - if currCase.expErr == unknErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errErr { - a.FailNow(fmt.Sprintf("case %s failed", currCase.id)) - } - } -} diff --git a/pkg/servregistry/etcd/service.go b/pkg/servregistry/etcd/service.go deleted file mode 100644 index fc5eebb..0000000 --- a/pkg/servregistry/etcd/service.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "context" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "gopkg.in/yaml.v3" -) - -// GetServ returns the service if exists. -func (e *EtcdServReg) GetServ(nsName, servName string) (*sr.Service, error) { - key, err := KeyFromServiceRegistryObject(&sr.Service{NsName: nsName, Name: servName}) - if err != nil { - return nil, err - } - - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - serv, err := e.getOne(ctx, key) - if err != nil { - return nil, err - } - - return serv.(*sr.Service), nil -} - -// ListServ returns a list of services inside the provided namespace. -func (e *EtcdServReg) ListServ(nsName string) (servList []*sr.Service, err error) { - if !KeyFromNames(nsName).IsValid() { - return nil, sr.ErrNsNameNotProvided - } - - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - err = e.getList(ctx, KeyFromNames(nsName), func(item []byte) { - var serv *sr.Service - if err := yaml.Unmarshal(item, &serv); err == nil { - servList = append(servList, serv) - return - } - }) - - if err != nil { - return nil, err - } - - return -} - -// CreateServ creates the service. -func (e *EtcdServReg) CreateServ(serv *sr.Service) (*sr.Service, error) { - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - if err := e.put(ctx, serv, false); err != nil { - return nil, err - } - - return serv, nil -} - -// UpdateServ updates the service. -func (e *EtcdServReg) UpdateServ(serv *sr.Service) (*sr.Service, error) { - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - if err := e.put(ctx, serv, true); err != nil { - return nil, err - } - - return serv, nil -} - -// DeleteServ deletes the service. -func (e *EtcdServReg) DeleteServ(nsName, servName string) error { - key, err := KeyFromServiceRegistryObject(&sr.Service{NsName: nsName, Name: servName}) - if err != nil { - return err - } - - ctx, canc := context.WithTimeout(e.mainCtx, defaultTimeout) - defer canc() - - return e.delete(ctx, key) -} diff --git a/pkg/servregistry/etcd/service_registry.go b/pkg/servregistry/etcd/service_registry.go deleted file mode 100644 index 5f0cc05..0000000 --- a/pkg/servregistry/etcd/service_registry.go +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "path" - "time" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "go.etcd.io/etcd/api/v3/v3rpc/rpctypes" - clientv3 "go.etcd.io/etcd/client/v3" - namespace "go.etcd.io/etcd/client/v3/namespace" - "gopkg.in/yaml.v3" - corev1 "k8s.io/api/core/v1" -) - -const ( - defaultPrefix string = "/service-registry/" - // timeout used when sending requests - // TODO: make this configurable or include context explicitly on each - // method (best way) - defaultTimeout time.Duration = time.Duration(15) * time.Second -) - -// EtcdServReg is a wrap around an etcd client that allows you to perform -// service registry operations on etcd, such as storing, updating, deleting -// or retrieving a namespace, service, or endpoint. -// It is an implementation of ServiceRegistry defined in -// https://github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry. -type EtcdServReg struct { - cli *clientv3.Client - kv clientv3.KV - prefix string - mainCtx context.Context -} - -// NewServiceRegistryWithEtcd returns an instance of ServiceRegistry as defined -// by with -// ETCD as a backend. -// https://pkg.go.dev/github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry#ServiceRegistry. -// -// If prefix is not nil, all data will be prefixed with the value you set on -// prefix, for example: -// /my-prefix/my-data. -// If you don't want any prefix, set the value of prefix to an empty string or -// just "/" and all keys will be prefixed by just "/". -// -// You may even specify a prefix with multiple slashes: for example, if you -// have multiple clusters/environments, a key could be: -// "cluster-1/service-registry". -// Be aware that any leading AND trailing slashes will be removed to prevent -// key paths errors, but will be inserted correctly automatically when calling -// any of its methods. -// -// Be careful with this value as it can potentially overwrite existing data. -// -// If context is not nil, it will be used as the main context upon which all -// queries to etcd will be based on. -// -// This method returns an error only if the client provided to it is nil. -func NewServiceRegistryWithEtcd(ctx context.Context, cli *clientv3.Client, prefix *string) *EtcdServReg { - // Use the default prefix (/service-registry), - // unless the prefix is not nil, in which case we use that one. - pref := parsePrefix(prefix) - - return &EtcdServReg{ - cli: cli, - kv: namespace.NewKV(cli.KV, pref), - prefix: pref, - mainCtx: ctx, - } -} - -func (e *EtcdServReg) ExtractData(ns *corev1.Namespace, serv *corev1.Service) (*sr.Namespace, *sr.Service, []*sr.Endpoint, error) { - // NOTE: on future versions, this function will be removed from service - // registry and moved to the broker instead: it's not this package's job - // to convert structs. - if ns == nil { - return nil, nil, nil, sr.ErrNsNotProvided - } - if serv == nil { - return nil, nil, nil, sr.ErrServNotProvided - } - - // Parse the namespace - namespaceData := &sr.Namespace{ - Name: ns.Name, - Metadata: ns.Annotations, - } - if namespaceData.Metadata == nil { - namespaceData.Metadata = map[string]string{} - } - - // Parse the service - // NOTE: we put metadata on the service in service directory, - // not on the endpoints - serviceData := &sr.Service{ - Name: serv.Name, - NsName: ns.Name, - Metadata: serv.Annotations, - } - if serviceData.Metadata == nil { - serviceData.Metadata = map[string]string{} - } - - // Get the endpoints from the service - // First, build the ips - ips := []string{} - // TODO: check if Spec is nil - // TODO: check if ExternalIPS is not nil - // ^ this will be performed on the new version of ExternalData - ips = append(ips, serv.Spec.ExternalIPs...) - - // Get data from load balancers - for _, ing := range serv.Status.LoadBalancer.Ingress { - ips = append(ips, ing.IP) - } - - endpointsData := []*sr.Endpoint{} - for _, port := range serv.Spec.Ports { - for _, ip := range ips { - - // Create an hashed name for this - toBeHashed := fmt.Sprintf("%s-%d", ip, port.Port) - h := sha256.New() - h.Write([]byte(toBeHashed)) - hash := hex.EncodeToString(h.Sum(nil)) - - // Only take the first 10 characters of the hashed name - name := fmt.Sprintf("%s-%s", serv.Name, hash[:10]) - endpointsData = append(endpointsData, &sr.Endpoint{ - Name: name, - NsName: namespaceData.Name, - ServName: serviceData.Name, - Address: ip, - Port: port.Port, - Metadata: map[string]string{}, - }) - } - } - - return namespaceData, serviceData, endpointsData, nil -} - -func (e *EtcdServReg) getOne(ctx context.Context, key *KeyBuilder) (interface{}, error) { - // This function is not exported and thus is only for internal purpose - // only: any checks and validations are performed by the caller - // and not here. - resp, err := e.kv.Get(ctx, key.String(), clientv3.WithLimit(1)) - if err != nil { - if err == rpctypes.ErrGRPCKeyNotFound { - return nil, sr.ErrNotFound - } - return nil, err - } - - if len(resp.Kvs) == 0 { - return nil, sr.ErrNotFound - } - - switch key.ObjectType() { - case NamespaceObject: - var ns sr.Namespace - if err := yaml.Unmarshal(resp.Kvs[0].Value, &ns); err != nil { - return nil, err - } - return &ns, err - case ServiceObject: - var serv sr.Service - if err := yaml.Unmarshal(resp.Kvs[0].Value, &serv); err != nil { - return nil, err - } - return &serv, err - case EndpointObject: - var endp sr.Endpoint - if err := yaml.Unmarshal(resp.Kvs[0].Value, &endp); err != nil { - return nil, err - } - return &endp, err - default: - return nil, ErrUnknownObject - } -} - -func (e *EtcdServReg) getList(ctx context.Context, key *KeyBuilder, each func([]byte)) error { - var objectsToFind ObjectType - var suffix string - if key == nil { - key = &KeyBuilder{} - } - - switch key.ObjectType() { - case NamespaceObject: - objectsToFind = ServiceObject - suffix = string(servicePrefix) - case ServiceObject: - objectsToFind = EndpointObject - suffix = string(endpointPrefix) - default: - objectsToFind = NamespaceObject - suffix = string(namespacePrefix) - } - - actualKey := path.Join(key.String(), suffix) - resp, err := e.kv.Get(ctx, actualKey, clientv3.WithPrefix()) - if err != nil { - if err == rpctypes.ErrGRPCKeyNotFound { - return sr.ErrNotFound - } - return err - } - - for _, currentKV := range resp.Kvs { - currentKey := string(currentKV.Key) - if KeyFromString(currentKey).ObjectType() != objectsToFind { - continue - } - - if each != nil { - each(currentKV.Value) - } - } - - return nil -} - -func (e *EtcdServReg) put(ctx context.Context, object interface{}, update bool) error { - if object == nil { - return ErrNilObject - } - - key, err := KeyFromServiceRegistryObject(object) - if err != nil { - return err - } - - // As per documentation, "Conflicting names result in a runtime error." - // We handle service registry objects, which do not suffer from this. - // Therefore, there is no need to check the error here. - bytes, _ := yaml.Marshal(object) - - // revision == 0 means does not exist - cmp := "=" - if update { - // revision > 0 means that it does exist - cmp = ">" - } - - conditions := []clientv3.Cmp{} - elses := []clientv3.Op{} - - if key.ObjectType() >= ServiceObject { - nsKey := KeyFromNames(key.GetNamespace()) - conditions = append(conditions, clientv3.Compare(clientv3.CreateRevision(nsKey.String()), ">", 0)) - elses = append(elses, clientv3.OpGet(nsKey.String(), clientv3.WithCountOnly())) - - if key.ObjectType() == EndpointObject { - servKey := KeyFromNames(key.GetNamespace(), key.GetService()) - conditions = append(conditions, clientv3.Compare(clientv3.CreateRevision(servKey.String()), ">", 0)) - elses = append(elses, clientv3.OpGet(servKey.String(), clientv3.WithCountOnly())) - } - } - - conditions = append(conditions, clientv3.Compare(clientv3.CreateRevision(key.String()), cmp, 0)) - createIt := clientv3.OpPut(key.String(), string(bytes)) - - resp, err := e.kv.Txn(ctx).If(conditions...).Then(createIt).Else(elses...).Commit() - if err != nil { - return err - } - - if resp.Succeeded { - // All ok - return nil - } - - if len(resp.Responses) > 0 { - if resp.Responses[0].GetResponseRange().Count == 0 { - return fmt.Errorf("namespace with name %s does not exist", key.GetNamespace()) - } - - if len(resp.Responses) == 2 && resp.Responses[1].GetResponseRange().Count == 0 { - return fmt.Errorf("service with name %s does not exist", key.GetService()) - } - } - - if !update { - return sr.ErrAlreadyExists - } - - return sr.ErrNotFound -} - -func (e *EtcdServReg) delete(ctx context.Context, key *KeyBuilder) error { - condition := clientv3.Compare(clientv3.CreateRevision(key.String()), ">", 0) - - // We need to remove all children elements. - // The user must check if they care about them manually. (i.e. the broker - // will have to check this). - deleteIt := clientv3.OpDelete(key.String(), clientv3.WithPrefix()) - - resp, err := e.kv.Txn(ctx).If(condition).Then(deleteIt).Commit() - if err != nil { - return err - } - - if resp.Succeeded { - // All ok - return nil - } - - return sr.ErrNotFound -} diff --git a/pkg/servregistry/etcd/service_registry_test.go b/pkg/servregistry/etcd/service_registry_test.go deleted file mode 100644 index 5b60c21..0000000 --- a/pkg/servregistry/etcd/service_registry_test.go +++ /dev/null @@ -1,860 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "path" - "testing" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/stretchr/testify/assert" - "go.etcd.io/etcd/api/v3/mvccpb" - "go.etcd.io/etcd/api/v3/v3rpc/rpctypes" - clientv3 "go.etcd.io/etcd/client/v3" - "gopkg.in/yaml.v3" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestNewServiceRegistryWithEtcd(t *testing.T) { - a := assert.New(t) - - prefix := "something" - res := NewServiceRegistryWithEtcd(context.Background(), &clientv3.Client{}, &prefix) - a.NotNil(res) -} - -func TestGetOne(t *testing.T) { - a := assert.New(t) - unknErr := fmt.Errorf("unknown") - e := &EtcdServReg{} - ns := &sr.Namespace{ - Name: "namespace-name", - Metadata: map[string]string{ - "env": "beta", - }, - } - nsBytes, _ := yaml.Marshal(ns) - serv := &sr.Service{ - NsName: ns.Name, - Name: "service-name", - Metadata: map[string]string{ - "version": "v0.2.1", - }, - } - servBytes, _ := yaml.Marshal(serv) - endp := &sr.Endpoint{ - NsName: ns.Name, - ServName: serv.Name, - Name: "endpoint-name", - Metadata: map[string]string{ - "protocol": "tcp", - }, - } - endpBytes, _ := yaml.Marshal(endp) - - cases := []struct { - get func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) - key *KeyBuilder - expObj interface{} - expErr error - }{ - { - key: KeyFromNames(ns.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return nil, rpctypes.ErrGRPCKeyNotFound - }, - expErr: sr.ErrNotFound, - }, - { - key: KeyFromNames(ns.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return nil, fmt.Errorf("any error") - }, - expErr: unknErr, - }, - { - key: KeyFromNames(ns.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{}, - }, nil - }, - expErr: sr.ErrNotFound, - }, - { - key: KeyFromNames(ns.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - { - Value: []byte("invalid"), - }, - }, - }, nil - }, - expErr: unknErr, - }, - { - key: KeyFromNames(serv.NsName, serv.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - { - Value: []byte("invalid"), - }, - }, - }, nil - }, - expErr: unknErr, - }, - { - key: KeyFromNames(endp.NsName, endp.ServName, endp.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - { - Value: []byte("invalid"), - }, - }, - }, nil - }, - expErr: unknErr, - }, - { - key: KeyFromNames(), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - { - Value: []byte("invalid"), - }, - }, - }, nil - }, - expErr: ErrUnknownObject, - }, - { - key: KeyFromNames(ns.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - { - Value: nsBytes, - }, - }, - }, nil - }, - expObj: ns, - }, - { - key: KeyFromNames(serv.NsName, serv.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - { - Value: servBytes, - }, - }, - }, nil - }, - expObj: serv, - }, - { - key: KeyFromNames(endp.NsName, endp.ServName, endp.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - { - Value: endpBytes, - }, - }, - }, nil - }, - expObj: endp, - }, - } - - for i, currCase := range cases { - f := &fakeKV{ - _get: currCase.get, - } - e.kv = f - - var errErr bool - res, err := e.getOne(context.Background(), currCase.key) - - errRes := a.Equal(currCase.expObj, res) - if currCase.expErr == unknErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestGetList(t *testing.T) { - a := assert.New(t) - unknErr := fmt.Errorf("unknown") - e := &EtcdServReg{mainCtx: context.Background()} - nsSearchPref := string(namespacePrefix) - ns := &sr.Namespace{ - Name: "namespace-name", - Metadata: map[string]string{ - "env": "beta", - }, - } - nsBytes, _ := yaml.Marshal(ns) - servSearchPref := path.Join(string(namespacePrefix), ns.Name, string(servicePrefix)) - serv := &sr.Service{ - NsName: ns.Name, - Name: "service-name", - Metadata: map[string]string{ - "version": "v0.2.1", - }, - } - endpSearchPref := path.Join(string(namespacePrefix), ns.Name, string(servicePrefix), serv.Name, string(endpointPrefix)) - servBytes, _ := yaml.Marshal(serv) - endp := &sr.Endpoint{ - NsName: ns.Name, - ServName: serv.Name, - Name: "endpoint-name", - Metadata: map[string]string{ - "protocol": "tcp", - }, - } - endpBytes, _ := yaml.Marshal(endp) - - cases := []struct { - id string - get func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) - key *KeyBuilder - each func([]byte) - expErr error - }{ - { - id: "nil-key-check-search-prefix", - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - if !a.Equal(nsSearchPref, key) { - a.FailNow("case 0: key failed") - } - return nil, fmt.Errorf("just to stop the execution") - }, - expErr: unknErr, - }, - { - id: "not-nil-key-check-search-prefix", - key: &KeyBuilder{}, - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - if !a.Equal(nsSearchPref, key) { - a.FailNow("case 1: key failed") - } - return nil, fmt.Errorf("just to stop the execution") - }, - expErr: unknErr, - }, - { - id: "ns-key-check-search-prefix", - key: KeyFromNames(ns.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - if !a.Equal(servSearchPref, key) { - a.FailNow("case 2: key failed") - } - return nil, fmt.Errorf("just to stop the execution") - }, - expErr: unknErr, - }, - { - id: "serv-key-check-search-prefix", - key: KeyFromNames(ns.Name, serv.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - if !a.Equal(endpSearchPref, key) { - a.FailNow("case 3: key failed") - } - return nil, fmt.Errorf("just to stop the execution") - }, - expErr: unknErr, - }, - { - id: "should-return-ErrGRPCKeyNotFound", - key: KeyFromNames(ns.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return nil, rpctypes.ErrGRPCKeyNotFound - }, - expErr: sr.ErrNotFound, - }, - { - id: "should-return-empty-kvs", - key: KeyFromNames(ns.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{}, - }, nil - }, - }, - { - id: "should-call-each-func-on-ns", - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - {Key: []byte(KeyFromNames(ns.Name, serv.Name, endp.Name).String()), Value: endpBytes}, - {Key: []byte(KeyFromNames(ns.Name, serv.Name).String()), Value: servBytes}, - {Key: []byte(KeyFromNames(ns.Name).String()), Value: nsBytes}, - }, - }, nil - }, - each: func(b []byte) { - if !a.Equal(nsBytes, b) { - a.FailNow("case 6: object provided is not correct") - } - }, - }, - { - id: "should-call-each-func-on-ns", - key: &KeyBuilder{}, - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - {Key: []byte(KeyFromNames(ns.Name, serv.Name, endp.Name).String()), Value: endpBytes}, - {Key: []byte(KeyFromNames(ns.Name, serv.Name).String()), Value: servBytes}, - {Key: []byte(KeyFromNames(ns.Name).String()), Value: nsBytes}, - }, - }, nil - }, - each: func(b []byte) { - if !a.Equal(nsBytes, b) { - a.FailNow("case 7: object provided is not correct") - } - }, - }, - { - id: "should-call-each-func-on-serv", - key: KeyFromNames(ns.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - {Key: []byte(KeyFromNames(ns.Name, serv.Name, endp.Name).String()), Value: endpBytes}, - {Key: []byte(KeyFromNames(ns.Name).String()), Value: nsBytes}, - {Key: []byte(KeyFromNames(ns.Name, serv.Name).String()), Value: servBytes}, - }, - }, nil - }, - each: func(b []byte) { - if !a.Equal(servBytes, b) { - a.FailNow("case 8: object provided is not correct") - } - }, - }, - { - id: "should-call-each-func-on-endp", - key: KeyFromNames(ns.Name, serv.Name), - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - {Key: []byte(KeyFromNames(ns.Name, serv.Name).String()), Value: servBytes}, - {Key: []byte(KeyFromNames(ns.Name).String()), Value: nsBytes}, - {Key: []byte(KeyFromNames(ns.Name, serv.Name, endp.Name).String()), Value: endpBytes}, - }, - }, nil - }, - each: func(b []byte) { - if !a.Equal(endpBytes, b) { - a.FailNow("case 9: object provided is not correct") - } - }, - }, - } - - for i, currCase := range cases { - e.kv = &fakeKV{ - _get: currCase.get, - } - - var errErr bool - err := e.getList(e.mainCtx, currCase.key, currCase.each) - if currCase.expErr == unknErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} -func TestPut(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{} - txn := &fakeTXN{} - txn._if = func(cs ...clientv3.Cmp) clientv3.Txn { - return txn - } - txn._then = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - txn._else = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - unknErr := fmt.Errorf("unknown") - - cases := []struct { - obj interface{} - commit func() (*clientv3.TxnResponse, error) - upd bool - expErr error - }{ - { - expErr: ErrNilObject, - }, - { - obj: &sr.Namespace{}, - expErr: sr.ErrNsNameNotProvided, - }, - { - obj: &sr.Service{NsName: "namespace-name"}, - expErr: sr.ErrServNameNotProvided, - }, - { - obj: &sr.Endpoint{NsName: "namespace-name", ServName: "service-name"}, - expErr: sr.ErrEndpNameNotProvided, - }, - { - obj: &sr.Endpoint{NsName: "namespace-name", ServName: "service-name"}, - expErr: sr.ErrEndpNameNotProvided, - }, - } - - for i, currCase := range cases { - f := &fakeKV{} - f._txn = func(ctx context.Context) clientv3.Txn { - return txn - } - txn._commit = currCase.commit - e.kv = f - - var errErr bool - err := e.put(context.Background(), currCase.obj, currCase.upd) - if currCase.expErr == unknErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestDelete(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{} - txn := &fakeTXN{} - txn._if = func(cs ...clientv3.Cmp) clientv3.Txn { - return txn - } - txn._then = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - unknErr := fmt.Errorf("unknown") - - cases := []struct { - id string - key *KeyBuilder - commit func() (*clientv3.TxnResponse, error) - expErr error - }{ - { - key: KeyFromNames("anything"), - id: "returns-an-error", - commit: func() (*clientv3.TxnResponse, error) { - return nil, fmt.Errorf("any error") - }, - expErr: unknErr, - }, - { - key: KeyFromNames("anything"), - id: "is-not-successful", - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - }, nil - }, - expErr: sr.ErrNotFound, - }, - { - key: KeyFromNames("anything"), - id: "is-successful", - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: true, - }, nil - }, - }, - } - - for i, currCase := range cases { - f := &fakeKV{} - f._txn = func(ctx context.Context) clientv3.Txn { - return txn - } - txn._commit = currCase.commit - e.kv = f - - var errErr bool - err := e.delete(context.Background(), currCase.key) - if currCase.expErr == unknErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestExtractData(t *testing.T) { - a := assert.New(t) - nsName, servName := "ns", "serv" - e := &EtcdServReg{} - nsToTest := &corev1.Namespace{ - ObjectMeta: v1.ObjectMeta{ - Name: nsName, - }, - } - nsAnnotations := map[string]string{ - "key": "val", - } - ips := []string{"10.10.10.10", "11.11.11.11"} - ports := []int32{3333, 4444} - servToTest := &corev1.Service{ - ObjectMeta: v1.ObjectMeta{ - Name: servName, - Namespace: nsName, - }, - Spec: corev1.ServiceSpec{ - ExternalIPs: ips, - Ports: []corev1.ServicePort{ - { - Port: ports[0], - Name: "3333", - }, - { - Port: ports[1], - Name: "4444", - }, - }, - }, - } - servAnnotations := map[string]string{ - "key": "val", - } - statusIPS := []string{"20.20.20.20", "21.21.21.21"} - servStatus := corev1.ServiceStatus{ - LoadBalancer: corev1.LoadBalancerStatus{ - Ingress: []corev1.LoadBalancerIngress{ - {IP: statusIPS[0]}, - {IP: statusIPS[1]}, - }, - }, - } - - cases := []struct { - id string - ns *corev1.Namespace - serv *corev1.Service - expNs *sr.Namespace - expServ *sr.Service - expEndp []*sr.Endpoint - expErr error - }{ - { - id: "empty-ns", - expErr: sr.ErrNsNotProvided, - }, - { - id: "empty-serv", - ns: &corev1.Namespace{}, - expErr: sr.ErrServNotProvided, - }, - { - id: "empty-metadatas-external-ips", - ns: nsToTest, - serv: servToTest, - expNs: &sr.Namespace{Name: nsToTest.Name, Metadata: map[string]string{}}, - expServ: &sr.Service{NsName: servToTest.Namespace, Name: servToTest.Name, Metadata: map[string]string{}}, - expEndp: []*sr.Endpoint{ - { - NsName: servToTest.Namespace, - ServName: servToTest.Name, - Name: func() string { - toBeHashed := fmt.Sprintf("%s-%d", ips[0], servToTest.Spec.Ports[0].Port) - h := sha256.New() - h.Write([]byte(toBeHashed)) - return fmt.Sprintf("%s-%s", servToTest.Name, hex.EncodeToString(h.Sum(nil))[:10]) - }(), - Address: ips[0], - Port: servToTest.Spec.Ports[0].Port, - Metadata: map[string]string{}, - }, - { - NsName: servToTest.Namespace, - ServName: servToTest.Name, - Name: func() string { - toBeHashed := fmt.Sprintf("%s-%d", ips[0], servToTest.Spec.Ports[1].Port) - h := sha256.New() - h.Write([]byte(toBeHashed)) - return fmt.Sprintf("%s-%s", servToTest.Name, hex.EncodeToString(h.Sum(nil))[:10]) - }(), - Address: ips[0], - Port: servToTest.Spec.Ports[1].Port, - Metadata: map[string]string{}, - }, - { - NsName: servToTest.Namespace, - ServName: servToTest.Name, - Name: func() string { - toBeHashed := fmt.Sprintf("%s-%d", ips[1], servToTest.Spec.Ports[0].Port) - h := sha256.New() - h.Write([]byte(toBeHashed)) - return fmt.Sprintf("%s-%s", servToTest.Name, hex.EncodeToString(h.Sum(nil))[:10]) - }(), - Address: ips[1], - Port: servToTest.Spec.Ports[0].Port, - Metadata: map[string]string{}, - }, - { - NsName: servToTest.Namespace, - ServName: servToTest.Name, - Name: func() string { - toBeHashed := fmt.Sprintf("%s-%d", ips[1], servToTest.Spec.Ports[1].Port) - h := sha256.New() - h.Write([]byte(toBeHashed)) - return fmt.Sprintf("%s-%s", servToTest.Name, hex.EncodeToString(h.Sum(nil))[:10]) - }(), - Address: ips[1], - Port: servToTest.Spec.Ports[1].Port, - Metadata: map[string]string{}, - }, - }, - }, - { - id: "not-empty-metadatas-ingress-ips", - ns: func() *corev1.Namespace { - n := nsToTest.DeepCopy() - n.Annotations = nsAnnotations - return n - }(), - serv: func() *corev1.Service { - s := servToTest.DeepCopy() - s.Spec.ExternalIPs = []string{} - s.Status = servStatus - s.Annotations = servAnnotations - return s - }(), - expNs: &sr.Namespace{Name: nsToTest.Name, Metadata: nsAnnotations}, - expServ: &sr.Service{NsName: servToTest.Namespace, Name: servToTest.Name, Metadata: servAnnotations}, - expEndp: []*sr.Endpoint{ - { - NsName: servToTest.Namespace, - ServName: servToTest.Name, - Name: func() string { - toBeHashed := fmt.Sprintf("%s-%d", statusIPS[0], servToTest.Spec.Ports[0].Port) - h := sha256.New() - h.Write([]byte(toBeHashed)) - return fmt.Sprintf("%s-%s", servToTest.Name, hex.EncodeToString(h.Sum(nil))[:10]) - }(), - Address: statusIPS[0], - Port: servToTest.Spec.Ports[0].Port, - Metadata: map[string]string{}, - }, - { - NsName: servToTest.Namespace, - ServName: servToTest.Name, - Name: func() string { - toBeHashed := fmt.Sprintf("%s-%d", statusIPS[0], servToTest.Spec.Ports[1].Port) - h := sha256.New() - h.Write([]byte(toBeHashed)) - return fmt.Sprintf("%s-%s", servToTest.Name, hex.EncodeToString(h.Sum(nil))[:10]) - }(), - Address: statusIPS[0], - Port: servToTest.Spec.Ports[1].Port, - Metadata: map[string]string{}, - }, - { - NsName: servToTest.Namespace, - ServName: servToTest.Name, - Name: func() string { - toBeHashed := fmt.Sprintf("%s-%d", statusIPS[1], servToTest.Spec.Ports[0].Port) - h := sha256.New() - h.Write([]byte(toBeHashed)) - return fmt.Sprintf("%s-%s", servToTest.Name, hex.EncodeToString(h.Sum(nil))[:10]) - }(), - Address: statusIPS[1], - Port: servToTest.Spec.Ports[0].Port, - Metadata: map[string]string{}, - }, - { - NsName: servToTest.Namespace, - ServName: servToTest.Name, - Name: func() string { - toBeHashed := fmt.Sprintf("%s-%d", statusIPS[1], servToTest.Spec.Ports[1].Port) - h := sha256.New() - h.Write([]byte(toBeHashed)) - return fmt.Sprintf("%s-%s", servToTest.Name, hex.EncodeToString(h.Sum(nil))[:10]) - }(), - Address: statusIPS[1], - Port: servToTest.Spec.Ports[1].Port, - Metadata: map[string]string{}, - }, - }, - }, - } - - for _, currCase := range cases { - n, s, e, err := e.ExtractData(currCase.ns, currCase.serv) - errN := a.Equal(currCase.expNs, n) - errS := a.Equal(currCase.expServ, s) - errErr := a.Equal(currCase.expErr, err) - errLen := a.Len(e, len(currCase.expEndp)) - // errE := a.Equal(currCase.expEndp, e) - - for _, eEndp := range currCase.expEndp { - found := false - - for _, endp := range e { - if endp.Name == eEndp.Name { - found = true - if !a.Equal(eEndp, endp) { - a.FailNow("case %s failed", currCase.id) - } - break - } - } - - if !found { - a.FailNow("case %s failed: endpoint %s not found", currCase.id, eEndp.Name) - } - } - - if !errN || !errS || /*!errE ||*/ !errErr || !errLen { - a.FailNow(fmt.Sprintf("case %s failed", currCase.id)) - } - } - - // statusIPS := []string{"20.20.20.20", "21.21.21.21", "22.22.22.22"} - // servStatus := corev1.ServiceStatus{ - // LoadBalancer: corev1.LoadBalancerStatus{ - // Ingress: []corev1.LoadBalancerIngress{ - // {IP: "20.20.20.20"}, - // {IP: "21.21.21.21"}, - // {IP: "22.22.22.22"}, - // }, - // }, - // } - - // a := assert.New(t) - - // ns, serv, endp, err := e.ExtractData(nsToTest, nil) - // a.Nil(ns) - // a.Nil(serv) - // a.Nil(endp) - // a.Equal(sr.ErrServNotProvided, err) - - // ns, serv, endp, err = e.ExtractData(nil, servToTest) - // a.Nil(ns) - // a.Nil(serv) - // a.Nil(endp) - // a.Equal(sr.ErrNsNotProvided, err) - - // ns, serv, endp, err = e.ExtractData(nsToTest, servToTest) - // a.NotNil(ns) - // a.NotNil(serv) - // a.NotNil(endp) - // a.NoError(err) - // a.Equal(&sr.Namespace{ - // Name: nsName, - // Metadata: nsToTest.Annotations, - // }, ns) - // a.Equal(&sr.Service{ - // Name: servName, - // NsName: nsName, - // Metadata: servToTest.Annotations, - // }, serv) - // a.Len(endp, 4) - // for _, e := range endp { - // a.Contains(ips, e.Address) - // a.Contains(ports, e.Port) - // a.Empty(e.Metadata) - // a.Equal(nsName, e.NsName) - // a.Equal(servName, e.ServName) - - // if !strings.HasPrefix(e.Name, servName+"-") { - // a.Fail("endpoint name is incorrect. Should start with", servName, "but is", e.Name) - // } - - // suffix := e.Name[len(servName)+1:] - // a.Len(suffix, 10) - // } - - // servToTest.Status = servStatus - // ns, serv, endp, err = e.ExtractData(nsToTest, servToTest) - // a.NotNil(ns) - // a.NotNil(serv) - // a.NotNil(endp) - // a.NoError(err) - // a.Equal(&sr.Namespace{ - // Name: nsName, - // Metadata: nsToTest.Annotations, - // }, ns) - // a.Equal(&sr.Service{ - // Name: servName, - // NsName: nsName, - // Metadata: servToTest.Annotations, - // }, serv) - // expIPS := []string{} - // expIPS = append(expIPS, ips...) - // expIPS = append(expIPS, statusIPS...) - // a.Len(endp, len(expIPS)*len(servToTest.Spec.Ports)) - // for _, e := range endp { - // a.Contains(expIPS, e.Address) - // a.Contains(ports, e.Port) - // a.Empty(e.Metadata) - // a.Equal(nsName, e.NsName) - // a.Equal(servName, e.ServName) - - // if !strings.HasPrefix(e.Name, servName+"-") { - // a.Fail("endpoint name is incorrect. Should start with", servName, "but is", e.Name) - // } - - // suffix := e.Name[len(servName)+1:] - // a.Len(suffix, 10) - // } -} diff --git a/pkg/servregistry/etcd/service_test.go b/pkg/servregistry/etcd/service_test.go deleted file mode 100644 index 9185f13..0000000 --- a/pkg/servregistry/etcd/service_test.go +++ /dev/null @@ -1,489 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "context" - "fmt" - "testing" - - "go.etcd.io/etcd/api/v3/etcdserverpb" - "go.etcd.io/etcd/api/v3/mvccpb" - clientv3 "go.etcd.io/etcd/client/v3" - "gopkg.in/yaml.v3" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/stretchr/testify/assert" -) - -func TestGetServ(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{ - mainCtx: context.Background(), - } - unknownErr := fmt.Errorf("unknwon") - serv := &sr.Service{ - NsName: "namespace-name", - Name: "service-name", - Metadata: map[string]string{"v": "v0.2.1"}, - } - servBytes, _ := yaml.Marshal(serv) - cases := []struct { - get func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) - nsName string - name string - expRes *sr.Service - expErr error - }{ - { - expErr: sr.ErrNsNameNotProvided, - }, - { - nsName: serv.NsName, - expErr: sr.ErrServNameNotProvided, - }, - { - nsName: serv.NsName, - name: serv.Name, - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - // errors are already tested in getOne - return nil, fmt.Errorf("any error") - }, - expErr: unknownErr, - }, - { - nsName: serv.NsName, - name: serv.Name, - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - { - Value: servBytes, - }, - }, - }, nil - }, - expRes: serv, - }, - } - - for i, currCase := range cases { - f := &fakeKV{ - _get: currCase.get, - } - e.kv = f - - var errErr bool - res, err := e.GetServ(currCase.nsName, currCase.name) - errRes := a.Equal(currCase.expRes, res) - - if currCase.expErr == unknownErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestListServ(t *testing.T) { - a := assert.New(t) - unknErr := fmt.Errorf("unknown") - e := &EtcdServReg{mainCtx: context.Background()} - serv := &sr.Service{ - NsName: "namespace-name", - Name: "service-name", - Metadata: map[string]string{ - "env": "beta", - }, - } - serv2 := &sr.Service{ - NsName: serv.Name, - Name: "namespace-name-2", - Metadata: map[string]string{ - "env": "prod", - }, - } - servBytes, _ := yaml.Marshal(serv) - servBytes2, _ := yaml.Marshal(serv2) - invalid := []byte(`name: invalid - name: invalid2`) - - cases := []struct { - id string - nsName string - get func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) - expRes []*sr.Service - expErr error - }{ - { - id: "empty-ns-name", - expErr: sr.ErrNsNameNotProvided, - }, - { - id: "any-error", // all the specific errors are tested in TestGetList - nsName: serv.NsName, - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return nil, fmt.Errorf("any error") - }, - expErr: unknErr, - }, - { - id: "should-marshal-some", - nsName: serv.NsName, - get: func(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { - return &clientv3.GetResponse{ - Kvs: []*mvccpb.KeyValue{ - {Key: []byte(KeyFromNames(serv.NsName, serv.Name).String()), Value: servBytes}, - {Key: []byte(KeyFromNames(serv2.NsName, serv2.Name).String()), Value: servBytes2}, - {Key: []byte(KeyFromNames("whatever", "invalid").String()), Value: invalid}, - }, - }, nil - }, - expRes: []*sr.Service{serv, serv2}, - }, - } - - for _, currCase := range cases { - e.kv = &fakeKV{ - _get: currCase.get, - } - - var errErr bool - res, err := e.ListServ(currCase.nsName) - - errRes := a.Equal(currCase.expRes, res) - if currCase.expErr == unknErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %s failed", currCase.id)) - } - } -} -func TestCreateServ(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{ - mainCtx: context.Background(), - } - unknownErr := fmt.Errorf("unknwon") - serv := &sr.Service{ - NsName: "namespace-name", - Name: "service-name", - Metadata: map[string]string{"v": "v0.2.0"}, - } - txn := &fakeTXN{} - txn._if = func(cs ...clientv3.Cmp) clientv3.Txn { - return txn - } - txn._then = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - txn._else = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - - cases := []struct { - serv *sr.Service - commit func() (*clientv3.TxnResponse, error) - expRes *sr.Service - expErr error - }{ - { - serv: serv, - commit: func() (*clientv3.TxnResponse, error) { - // All other errors are tested in testPut - return nil, fmt.Errorf("any error") - }, - expErr: unknownErr, - }, - { - serv: serv, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: true, - }, nil - }, - expRes: serv, - }, - { - serv: serv, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - }, nil - }, - expErr: sr.ErrAlreadyExists, - }, - { - serv: serv, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - Responses: []*etcdserverpb.ResponseOp{ - { - Response: &etcdserverpb.ResponseOp_ResponseRange{ - ResponseRange: &etcdserverpb.RangeResponse{ - Count: 0, - }, - }, - }, - }, - }, nil - }, - expErr: fmt.Errorf("namespace with name %s does not exist", serv.NsName), - }, - { - serv: serv, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - Responses: []*etcdserverpb.ResponseOp{ - { - Response: &etcdserverpb.ResponseOp_ResponseRange{ - ResponseRange: &etcdserverpb.RangeResponse{ - Count: 1, - }, - }, - }, - }, - }, nil - }, - expErr: unknownErr, - }, - } - - for i, currCase := range cases { - f := &fakeKV{} - f._txn = func(ctx context.Context) clientv3.Txn { - return txn - } - txn._commit = currCase.commit - e.kv = f - - var errErr bool - res, err := e.CreateServ(currCase.serv) - errRes := a.Equal(currCase.expRes, res) - - if currCase.expErr == unknownErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestUpdateServ(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{ - mainCtx: context.Background(), - } - unknownErr := fmt.Errorf("unknwon") - serv := &sr.Service{ - NsName: "namespace-name", - Name: "service-name", - Metadata: map[string]string{"v": "v0.2.0"}, - } - txn := &fakeTXN{} - txn._if = func(cs ...clientv3.Cmp) clientv3.Txn { - return txn - } - txn._then = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - txn._else = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - - cases := []struct { - serv *sr.Service - commit func() (*clientv3.TxnResponse, error) - expRes *sr.Service - expErr error - }{ - { - serv: serv, - commit: func() (*clientv3.TxnResponse, error) { - // All other errors are tested in testPut - return nil, fmt.Errorf("any error") - }, - expErr: unknownErr, - }, - { - serv: serv, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: true, - }, nil - }, - expRes: serv, - }, - { - serv: serv, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - }, nil - }, - expErr: sr.ErrNotFound, - }, - { - serv: serv, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - Responses: []*etcdserverpb.ResponseOp{ - { - Response: &etcdserverpb.ResponseOp_ResponseRange{ - ResponseRange: &etcdserverpb.RangeResponse{ - Count: 0, - }, - }, - }, - }, - }, nil - }, - expErr: fmt.Errorf("namespace with name %s does not exist", serv.NsName), - }, - { - serv: serv, - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: false, - Responses: []*etcdserverpb.ResponseOp{ - { - Response: &etcdserverpb.ResponseOp_ResponseRange{ - ResponseRange: &etcdserverpb.RangeResponse{ - Count: 1, - }, - }, - }, - }, - }, nil - }, - expErr: unknownErr, - }, - } - - for i, currCase := range cases { - f := &fakeKV{} - f._txn = func(ctx context.Context) clientv3.Txn { - return txn - } - txn._commit = currCase.commit - e.kv = f - - var errErr bool - res, err := e.UpdateServ(currCase.serv) - errRes := a.Equal(currCase.expRes, res) - - if currCase.expErr == unknownErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errRes || !errErr { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} - -func TestDeleteServ(t *testing.T) { - a := assert.New(t) - e := &EtcdServReg{ - mainCtx: context.Background(), - } - txn := &fakeTXN{} - txn._if = func(cs ...clientv3.Cmp) clientv3.Txn { - return txn - } - txn._then = func(ops ...clientv3.Op) clientv3.Txn { - return txn - } - unknErr := fmt.Errorf("unknown") - - cases := []struct { - id string - nsName string - servName string - commit func() (*clientv3.TxnResponse, error) - expErr error - }{ - { - id: "empty-ns-name", - expErr: sr.ErrNsNameNotProvided, - }, - { - id: "empty-serv-name", - nsName: "ns-name", - expErr: sr.ErrServNameNotProvided, - }, - { - id: "returns-any-error", // specific errors are tested in TestDelete - nsName: "ns-name", - servName: "serv-name", - commit: func() (*clientv3.TxnResponse, error) { - return nil, fmt.Errorf("any error") - }, - expErr: unknErr, - }, - { - id: "is-successful", - nsName: "ns-name", - servName: "serv-name", - commit: func() (*clientv3.TxnResponse, error) { - return &clientv3.TxnResponse{ - Succeeded: true, - }, nil - }, - }, - } - - for _, currCase := range cases { - f := &fakeKV{} - f._txn = func(ctx context.Context) clientv3.Txn { - return txn - } - txn._commit = currCase.commit - e.kv = f - - var errErr bool - err := e.DeleteServ(currCase.nsName, currCase.servName) - if currCase.expErr == unknErr { - errErr = a.Error(err) - } else { - errErr = a.Equal(currCase.expErr, err) - } - - if !errErr { - a.FailNow(fmt.Sprintf("case %s failed", currCase.id)) - } - } -} diff --git a/pkg/servregistry/etcd/utils.go b/pkg/servregistry/etcd/utils.go deleted file mode 100644 index df23088..0000000 --- a/pkg/servregistry/etcd/utils.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "fmt" - "strings" -) - -func parsePrefix(prefix *string) string { - if prefix == nil { - return defaultPrefix - } - - if len(*prefix) == 0 || *prefix == "/" { - return "/" - } - - // Remove all slashes to prevent having values like //key//// - _prefix := strings.Trim(*prefix, "/") - return fmt.Sprintf("/%s/", _prefix) -} diff --git a/pkg/servregistry/etcd/utils_test.go b/pkg/servregistry/etcd/utils_test.go deleted file mode 100644 index 83ff8d8..0000000 --- a/pkg/servregistry/etcd/utils_test.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright © 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package etcd - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestParsePrefix(t *testing.T) { - a := assert.New(t) - empty := "" - onlySlash := "/" - multipleSlashes := "///test///" - - cases := []struct { - prefix *string - expRes string - }{ - { - expRes: defaultPrefix, - }, - { - prefix: &empty, - expRes: "/", - }, - { - prefix: &onlySlash, - expRes: "/", - }, - { - prefix: &multipleSlashes, - expRes: "/test/", - }, - } - - for i, currCase := range cases { - res := parsePrefix(currCase.prefix) - errRes := a.Equal(currCase.expRes, res) - if !errRes { - a.FailNow(fmt.Sprintf("case %d failed", i)) - } - } -} diff --git a/pkg/servregistry/gcloud/servicedirectory/doc.go b/pkg/servregistry/gcloud/servicedirectory/doc.go deleted file mode 100644 index 0ad8662..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/doc.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -// Package servicedirectory contains code that connects to Google Cloud -// Service Directory and performs some actions with specific resources. -// Examples of such actions are create, update or delete. -// Examples of such resources are namespaces, services or endpoints. -package servicedirectory diff --git a/pkg/servregistry/gcloud/servicedirectory/endpoint.go b/pkg/servregistry/gcloud/servicedirectory/endpoint.go deleted file mode 100644 index 701a85b..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/endpoint.go +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright © 2020, 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servicedirectory - -import ( - "context" - "strings" - "time" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "google.golang.org/api/iterator" - sdpb "google.golang.org/genproto/googleapis/cloud/servicedirectory/v1" - "google.golang.org/genproto/protobuf/field_mask" -) - -// GetEndp returns the endpoint if exists. -func (s *Handler) GetEndp(nsName, servName, endpName string) (*sr.Endpoint, error) { - // -- Init - if err := s.checkNames(&nsName, &servName, &endpName); err != nil { - return nil, err - } - - endpPath := s.getResourcePath(servDirPath{namespace: nsName, service: servName, endpoint: endpName}) - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - sdEndp, err := s.Client.GetEndpoint(ctx, &sdpb.GetEndpointRequest{Name: endpPath}) - if err == nil { - endp := &sr.Endpoint{ - Name: endpName, - NsName: nsName, - ServName: servName, - Metadata: sdEndp.Annotations, - } - if endp.Metadata == nil { - endp.Metadata = map[string]string{} - } - - return endp, nil - } - - return nil, castStatusToErr(err) -} - -// ListServ returns a list of services inside the provided namespace. -func (s *Handler) ListEndp(nsName, servName string) (endpList []*sr.Endpoint, err error) { - // -- Init - if err := s.checkNames(&nsName, &servName, nil); err != nil { - return nil, err - } - l := s.Log.WithName("ListEndp").WithValues("ns-name", nsName, "serv-name", servName) - ctx, canc := context.WithTimeout(s.Context, time.Minute) - defer canc() - - req := &sdpb.ListEndpointsRequest{ - Parent: s.getResourcePath(servDirPath{namespace: nsName, service: servName}), - } - - iter := s.Client.ListEndpoints(ctx, req) - if iter == nil { - l.V(0).Info("returned list is nil") - return - } - for { - nextEndp, iterErr := iter.Next() - if iterErr != nil { - - if iterErr == context.DeadlineExceeded { - l.Error(err, "timeout expired while waiting for service directory to reply", "timeout-seconds", defTimeout.Seconds()) - return nil, sr.ErrTimeOutExpired - } - - if iterErr != iterator.Done { - l.Error(iterErr, "error while loading endpoints") - return nil, iterErr - } - - break - } - - // Create the list - splitName := strings.Split(nextEndp.Name, "/") - endp := &sr.Endpoint{ - Name: splitName[len(splitName)-1], - ServName: servName, - NsName: nsName, - Metadata: nextEndp.Annotations, - } - if endp.Metadata == nil { - endp.Metadata = map[string]string{} - } - - endpList = append(endpList, endp) - } - - return -} - -// CreateEndp creates the endpoint. -func (s *Handler) CreateEndp(endp *sr.Endpoint) (*sr.Endpoint, error) { - // -- Init - if endp == nil { - return nil, sr.ErrEndpNotProvided - } - if err := s.checkNames(&endp.NsName, &endp.ServName, &endp.Name); err != nil { - return nil, err - } - - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - endpToCreate := &sdpb.Endpoint{ - Name: endp.Name, - Annotations: endp.Metadata, - Address: endp.Address, - Port: endp.Port, - } - - req := &sdpb.CreateEndpointRequest{ - Parent: s.getResourcePath(servDirPath{namespace: endp.NsName, service: endp.ServName}), - EndpointId: endp.Name, - Endpoint: endpToCreate, - } - - _, err := s.Client.CreateEndpoint(ctx, req) - if err == nil { - // If it is successful, then there is no point in parsing the returned - // service from service directory, because it will look like just the - // same as the service we want to create, apart from having prefixes - // in the name, which is something we want to abstract to someone - // using this. - return endp, nil - } - - return nil, castStatusToErr(err) -} - -// UpdateEndp updates the endpoint. -func (s *Handler) UpdateEndp(endp *sr.Endpoint) (*sr.Endpoint, error) { - // -- Init - if endp == nil { - return nil, sr.ErrEndpNotProvided - } - if err := s.checkNames(&endp.NsName, &endp.ServName, &endp.Name); err != nil { - return nil, err - } - - endpPath := s.getResourcePath(servDirPath{namespace: endp.NsName, service: endp.ServName, endpoint: endp.Name}) - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - endpToUpd := &sdpb.Endpoint{ - Name: endpPath, - Annotations: endp.Metadata, - Address: endp.Address, - Port: endp.Port, - } - - req := &sdpb.UpdateEndpointRequest{ - Endpoint: endpToUpd, - UpdateMask: &field_mask.FieldMask{ - Paths: []string{"annotations", "port", "address"}, - }, - } - - _, err := s.Client.UpdateEndpoint(ctx, req) - if err == nil { - return endp, nil - } - - return nil, castStatusToErr(err) -} - -// DeleteEndp deletes the endpoint. -func (s *Handler) DeleteEndp(nsName, servName, endpName string) error { - // -- Init - if err := s.checkNames(&nsName, &servName, &endpName); err != nil { - return err - } - - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - req := &sdpb.DeleteEndpointRequest{ - Name: s.getResourcePath(servDirPath{namespace: nsName, service: servName, endpoint: endpName}), - } - - err := s.Client.DeleteEndpoint(ctx, req) - if err == nil { - return nil - } - - return castStatusToErr(err) -} diff --git a/pkg/servregistry/gcloud/servicedirectory/endpoint_test.go b/pkg/servregistry/gcloud/servicedirectory/endpoint_test.go deleted file mode 100644 index 79caafa..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/endpoint_test.go +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servicedirectory - -import ( - "testing" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - a "github.com/stretchr/testify/assert" -) - -func TestGetEndp(t *testing.T) { - s := getFakeHandler() - nsName, servName, endpName := "ns", "serv", "endp" - - // Test errors - testErr := func(tt *testing.T) { - assert := a.New(tt) - - regEndp, err := s.GetEndp(nsName, servName, "get-error") - assert.Nil(regEndp) - assert.Error(err) - assert.NotEqual(sr.ErrTimeOutExpired, err) - assert.NotEqual(sr.ErrNotFound, err) - - regEndp, err = s.GetEndp(nsName, servName, "timeout-error") - assert.Nil(regEndp) - assert.Equal(sr.ErrTimeOutExpired, err) - - regEndp, err = s.GetEndp(nsName, servName, "get-not-found") - assert.Nil(regEndp) - assert.Equal(sr.ErrNotFound, err) - } - - // Test success on service directory - testOk := func(tt *testing.T) { - assert := a.New(tt) - - regEndp, err := s.GetEndp(nsName, servName, endpName) - assert.NotNil(regEndp) - assert.NoError(err) - assert.NotContains(regEndp.Name, "/") - assert.Equal(regEndp.NsName, nsName) - } - - testErr(t) - testOk(t) -} - -func TestCreateEndp(t *testing.T) { - s := getFakeHandler() - nsName, servName, endpName := "ns", "serv", "endp" - req := &sr.Endpoint{NsName: nsName, ServName: servName} - - // Test errors on service directory - testErr := func(tt *testing.T) { - assert := a.New(tt) - - regEndp, err := s.CreateEndp(nil) - assert.Nil(regEndp) - assert.Equal(sr.ErrEndpNotProvided, err) - - req.Name = "create-error" - regEndp, err = s.CreateEndp(req) - assert.Nil(regEndp) - assert.Error(err) - assert.NotEqual(sr.ErrTimeOutExpired, err) - assert.NotEqual(sr.ErrNotFound, err) - - req.Name = "timeout-error" - regEndp, err = s.CreateEndp(req) - assert.Nil(regEndp) - assert.Equal(sr.ErrTimeOutExpired, err) - - req.Name = "create-exists" - regEndp, err = s.CreateEndp(req) - assert.Nil(regEndp) - assert.Equal(sr.ErrAlreadyExists, err) - } - - // Test success on service directory - testOk := func(tt *testing.T) { - assert := a.New(tt) - - req.Name = endpName - regEndp, err := s.CreateEndp(req) - assert.NotNil(regEndp) - assert.NoError(err) - assert.NotContains(regEndp.Name, "/") - assert.Equal(regEndp.NsName, nsName) - assert.Equal(regEndp.ServName, servName) - } - - testErr(t) - testOk(t) -} - -func TestUpdateEndp(t *testing.T) { - s := getFakeHandler() - nsName, servName, endpName := "ns", "serv", "endp" - req := &sr.Endpoint{NsName: nsName, ServName: servName} - - // Test errors on service directory - testErr := func(tt *testing.T) { - assert := a.New(tt) - - regEndp, err := s.UpdateEndp(nil) - assert.Nil(regEndp) - assert.Equal(sr.ErrEndpNotProvided, err) - - req.Name = "update-error" - regEndp, err = s.UpdateEndp(req) - assert.Nil(regEndp) - assert.Error(err) - assert.NotEqual(sr.ErrTimeOutExpired, err) - assert.NotEqual(sr.ErrNotFound, err) - - req.Name = "timeout-error" - regEndp, err = s.UpdateEndp(req) - assert.Nil(regEndp) - assert.Equal(sr.ErrTimeOutExpired, err) - - req.Name = "update-not-found" - regEndp, err = s.UpdateEndp(req) - assert.Nil(regEndp) - assert.Equal(sr.ErrNotFound, err) - } - - // Test success on service directory - testOk := func(tt *testing.T) { - assert := a.New(tt) - - req.Name = endpName - regEndp, err := s.UpdateEndp(req) - assert.NotNil(regEndp) - assert.NoError(err) - assert.NotContains(regEndp.Name, "/") - assert.Equal(regEndp.NsName, nsName) - } - - testErr(t) - testOk(t) -} - -func TestDeleteEndp(t *testing.T) { - s := getFakeHandler() - nsName, servName, endpName := "ns", "serv", "endp" - - // Test errors on service directory - testErr := func(tt *testing.T) { - assert := a.New(tt) - - err := s.DeleteEndp(nsName, servName, "delete-error") - assert.Error(err) - assert.NotEqual(sr.ErrTimeOutExpired, err) - assert.NotEqual(sr.ErrNotFound, err) - - err = s.DeleteEndp(nsName, servName, "timeout-error") - assert.Equal(sr.ErrTimeOutExpired, err) - - err = s.DeleteEndp(nsName, servName, "delete-not-found") - assert.Equal(sr.ErrNotFound, err) - } - - // Test success on service directory - testOk := func(tt *testing.T) { - assert := a.New(tt) - - err := s.DeleteEndp(nsName, servName, endpName) - assert.NoError(err) - } - - testErr(t) - testOk(t) -} diff --git a/pkg/servregistry/gcloud/servicedirectory/fake_reg_client_test.go b/pkg/servregistry/gcloud/servicedirectory/fake_reg_client_test.go deleted file mode 100644 index 1ae91e9..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/fake_reg_client_test.go +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright © 2020, 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servicedirectory - -import ( - "context" - "errors" - "strings" - - sd "cloud.google.com/go/servicedirectory/apiv1" - "github.com/googleapis/gax-go/v2" - sdpb "google.golang.org/genproto/googleapis/cloud/servicedirectory/v1" - iampb "google.golang.org/genproto/googleapis/iam/v1" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "sigs.k8s.io/controller-runtime/pkg/log/zap" -) - -type fakeRegClient struct { -} - -func getFakeHandler() *Handler { - return &Handler{ - ProjectID: "project", - DefaultRegion: "us", - Context: context.Background(), - Client: &fakeRegClient{}, - Log: zap.New(zap.UseDevMode(true)), - } -} - -func (f *fakeRegClient) GetNamespace(ctx context.Context, req *sdpb.GetNamespaceRequest, opts ...gax.CallOption) (*sdpb.Namespace, error) { - split := strings.Split(req.Name, "/") - name := split[len(split)-1] - if name == "get-error" { - return nil, errors.New("error") - } - - if name == "get-not-found" { - return nil, status.Error(codes.NotFound, codes.NotFound.String()) - } - - if name == "timeout-error" { - return nil, status.Error(codes.DeadlineExceeded, codes.DeadlineExceeded.String()) - } - - return &sdpb.Namespace{Name: "one/two/three/four/five/ns"}, nil -} - -func (f *fakeRegClient) ListNamespaces(ctx context.Context, req *sdpb.ListNamespacesRequest, opts ...gax.CallOption) *sd.NamespaceIterator { - // Not mocked as currently not used by the operator - return nil -} - -func (f *fakeRegClient) CreateNamespace(ctx context.Context, req *sdpb.CreateNamespaceRequest, opts ...gax.CallOption) (*sdpb.Namespace, error) { - split := strings.Split(req.NamespaceId, "/") - name := split[len(split)-1] - if name == "create-error" { - return nil, errors.New("error") - } - - if name == "create-exists" { - return nil, status.Error(codes.AlreadyExists, codes.AlreadyExists.String()) - } - - if name == "timeout-error" { - return nil, status.Error(codes.DeadlineExceeded, codes.DeadlineExceeded.String()) - } - - return &sdpb.Namespace{Name: "one/two/three/four/five/ns"}, nil -} - -func (f *fakeRegClient) UpdateNamespace(ctx context.Context, req *sdpb.UpdateNamespaceRequest, opts ...gax.CallOption) (*sdpb.Namespace, error) { - split := strings.Split(req.Namespace.Name, "/") - name := split[len(split)-1] - if name == "update-error" { - return nil, errors.New("error") - } - - if name == "update-not-found" { - return nil, status.Error(codes.NotFound, codes.NotFound.String()) - } - - if name == "timeout-error" { - return nil, status.Error(codes.DeadlineExceeded, codes.DeadlineExceeded.String()) - } - - return &sdpb.Namespace{Name: "one/two/three/four/five/ns"}, nil -} - -func (f *fakeRegClient) DeleteNamespace(ctx context.Context, req *sdpb.DeleteNamespaceRequest, opts ...gax.CallOption) error { - split := strings.Split(req.Name, "/") - name := split[len(split)-1] - if name == "delete-error" { - return errors.New("error") - } - - if name == "delete-not-found" { - return status.Error(codes.NotFound, codes.NotFound.String()) - } - - if name == "timeout-error" { - return status.Error(codes.DeadlineExceeded, codes.DeadlineExceeded.String()) - } - - return nil -} - -func (f *fakeRegClient) GetService(ctx context.Context, req *sdpb.GetServiceRequest, opts ...gax.CallOption) (*sdpb.Service, error) { - split := strings.Split(req.Name, "/") - name := split[len(split)-1] - if name == "get-error" { - return nil, errors.New("error") - } - - if name == "get-not-found" { - return nil, status.Error(codes.NotFound, codes.NotFound.String()) - } - - if name == "timeout-error" { - return nil, status.Error(codes.DeadlineExceeded, codes.DeadlineExceeded.String()) - } - - return &sdpb.Service{Name: "one/two/three/four/five/six/seven/" + req.Name}, nil -} - -func (f *fakeRegClient) CreateService(ctx context.Context, req *sdpb.CreateServiceRequest, opts ...gax.CallOption) (*sdpb.Service, error) { - split := strings.Split(req.ServiceId, "/") - name := split[len(split)-1] - if name == "create-error" { - return nil, errors.New("error") - } - - if name == "create-exists" { - return nil, status.Error(codes.AlreadyExists, codes.AlreadyExists.String()) - } - - if name == "timeout-error" { - return nil, status.Error(codes.DeadlineExceeded, codes.DeadlineExceeded.String()) - } - - return &sdpb.Service{Name: "one/two/three/four/five/six/seven/" + req.ServiceId}, nil -} - -func (f *fakeRegClient) UpdateService(ctx context.Context, req *sdpb.UpdateServiceRequest, opts ...gax.CallOption) (*sdpb.Service, error) { - split := strings.Split(req.Service.Name, "/") - name := split[len(split)-1] - if name == "update-error" { - return nil, errors.New("error") - } - - if name == "update-not-found" { - return nil, status.Error(codes.NotFound, codes.NotFound.String()) - } - - if name == "timeout-error" { - return nil, status.Error(codes.DeadlineExceeded, codes.DeadlineExceeded.String()) - } - - return &sdpb.Service{Name: "one/two/three/four/five/ns"}, nil -} - -func (f *fakeRegClient) DeleteService(ctx context.Context, req *sdpb.DeleteServiceRequest, opts ...gax.CallOption) error { - split := strings.Split(req.Name, "/") - name := split[len(split)-1] - if name == "delete-error" { - return errors.New("error") - } - - if name == "delete-not-found" { - return status.Error(codes.NotFound, codes.NotFound.String()) - } - - if name == "timeout-error" { - return status.Error(codes.DeadlineExceeded, codes.DeadlineExceeded.String()) - } - - return nil -} - -func (f *fakeRegClient) GetEndpoint(ctx context.Context, req *sdpb.GetEndpointRequest, opts ...gax.CallOption) (*sdpb.Endpoint, error) { - split := strings.Split(req.Name, "/") - name := split[len(split)-1] - if name == "get-error" { - return nil, errors.New("error") - } - - if name == "get-not-found" { - return nil, status.Error(codes.NotFound, codes.NotFound.String()) - } - - if name == "timeout-error" { - return nil, status.Error(codes.DeadlineExceeded, codes.DeadlineExceeded.String()) - } - - return &sdpb.Endpoint{Name: "one/two/three/four/five/six/seven/eight/nine/" + req.Name}, nil -} - -func (f *fakeRegClient) CreateEndpoint(ctx context.Context, req *sdpb.CreateEndpointRequest, opts ...gax.CallOption) (*sdpb.Endpoint, error) { - split := strings.Split(req.EndpointId, "/") - name := split[len(split)-1] - if name == "create-error" { - return nil, errors.New("error") - } - - if name == "create-exists" { - return nil, status.Error(codes.AlreadyExists, codes.AlreadyExists.String()) - } - - if name == "timeout-error" { - return nil, status.Error(codes.DeadlineExceeded, codes.DeadlineExceeded.String()) - } - - return &sdpb.Endpoint{Name: "one/two/three/four/five/six/seven/eight/nine/" + req.EndpointId}, nil -} - -func (f *fakeRegClient) UpdateEndpoint(ctx context.Context, req *sdpb.UpdateEndpointRequest, opts ...gax.CallOption) (*sdpb.Endpoint, error) { - split := strings.Split(req.Endpoint.Name, "/") - name := split[len(split)-1] - if name == "update-error" { - return nil, errors.New("error") - } - - if name == "update-not-found" { - return nil, status.Error(codes.NotFound, codes.NotFound.String()) - } - - if name == "timeout-error" { - return nil, status.Error(codes.DeadlineExceeded, codes.DeadlineExceeded.String()) - } - - return &sdpb.Endpoint{Name: "one/two/three/four/five/six/seven/eight/nine/" + req.Endpoint.Name}, nil -} - -func (f *fakeRegClient) DeleteEndpoint(ctx context.Context, req *sdpb.DeleteEndpointRequest, opts ...gax.CallOption) error { - split := strings.Split(req.Name, "/") - name := split[len(split)-1] - if name == "delete-error" { - return errors.New("error") - } - - if name == "delete-not-found" { - return status.Error(codes.NotFound, codes.NotFound.String()) - } - - if name == "timeout-error" { - return status.Error(codes.DeadlineExceeded, codes.DeadlineExceeded.String()) - } - - return nil -} - -func (f *fakeRegClient) Close() error { return nil } - -func (f *fakeRegClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { - return nil, nil -} - -func (f *fakeRegClient) ListEndpoints(ctx context.Context, req *sdpb.ListEndpointsRequest, opts ...gax.CallOption) *sd.EndpointIterator { - return nil -} - -func (f *fakeRegClient) ListServices(ctx context.Context, req *sdpb.ListServicesRequest, opts ...gax.CallOption) *sd.ServiceIterator { - return nil -} -func (f *fakeRegClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { - return nil, nil -} -func (f *fakeRegClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { - return nil, nil -} diff --git a/pkg/servregistry/gcloud/servicedirectory/namespace.go b/pkg/servregistry/gcloud/servicedirectory/namespace.go deleted file mode 100644 index 1a39a61..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/namespace.go +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright © 2020, 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servicedirectory - -import ( - "context" - "strings" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "google.golang.org/api/iterator" - sdpb "google.golang.org/genproto/googleapis/cloud/servicedirectory/v1" - "google.golang.org/genproto/protobuf/field_mask" -) - -// GetNs returns the namespace if exists. -func (s *Handler) GetNs(name string) (*sr.Namespace, error) { - // -- Init - if err := s.checkNames(&name, nil, nil); err != nil { - return nil, err - } - - nsPath := s.getResourcePath(servDirPath{namespace: name}) - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - sdNs, err := s.Client.GetNamespace(ctx, &sdpb.GetNamespaceRequest{Name: nsPath}) - if err == nil { - namespace := &sr.Namespace{ - Name: name, - Metadata: sdNs.Labels, - } - if namespace.Metadata == nil { - namespace.Metadata = map[string]string{} - } - - return namespace, nil - } - - return nil, castStatusToErr(err) -} - -// ListNs returns a list of all namespaces. -func (s *Handler) ListNs() ([]*sr.Namespace, error) { - // -- Init - l := s.Log.WithName("ListNs") - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - req := &sdpb.ListNamespacesRequest{ - Parent: s.getResourcePath(servDirPath{}), - } - - nsList := []*sr.Namespace{} - iter := s.Client.ListNamespaces(ctx, req) - if iter == nil { - l.V(0).Info("returned list is nil") - return nsList, nil - } - for { - nextNs, iterErr := iter.Next() - if iterErr != nil { - - if iterErr == context.DeadlineExceeded { - l.Error(iterErr, "timeout expired while waiting for service directory to reply", "timeout-seconds", defTimeout.Seconds()) - return nil, sr.ErrTimeOutExpired - } - - if iterErr != iterator.Done { - l.Error(iterErr, "error while loading namespaces") - return nil, iterErr - } - - break - } - - splitName := strings.Split(nextNs.Name, "/") - ns := &sr.Namespace{ - Name: splitName[len(splitName)-1], - Metadata: nextNs.Labels, - } - if ns.Metadata == nil { - ns.Metadata = map[string]string{} - } - - nsList = append(nsList, ns) - } - - return nsList, nil -} - -// CreateNs creates the namespace. -func (s *Handler) CreateNs(ns *sr.Namespace) (*sr.Namespace, error) { - // -- Init - if ns == nil { - return nil, sr.ErrNsNotProvided - } - if err := s.checkNames(&ns.Name, nil, nil); err != nil { - return nil, err - } - - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - nsToCreate := &sdpb.Namespace{ - Name: ns.Name, - Labels: ns.Metadata, - } - - req := &sdpb.CreateNamespaceRequest{ - Parent: s.getResourcePath(servDirPath{}), - NamespaceId: ns.Name, - Namespace: nsToCreate, - } - - _, err := s.Client.CreateNamespace(ctx, req) - if err == nil { - // No need to parse the returned resource, because it is the same - // resource we want to add. So we can just returned the one we - // want to add. - return ns, nil - } - - return nil, castStatusToErr(err) -} - -// UpdateNs updates the namespace. -func (s *Handler) UpdateNs(ns *sr.Namespace) (*sr.Namespace, error) { - // -- Init - if ns == nil { - return nil, sr.ErrNsNotProvided - } - if err := s.checkNames(&ns.Name, nil, nil); err != nil { - return nil, err - } - - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - nsToUpd := &sdpb.Namespace{ - Name: s.getResourcePath(servDirPath{namespace: ns.Name}), - Labels: ns.Metadata, - } - - req := &sdpb.UpdateNamespaceRequest{ - Namespace: nsToUpd, - UpdateMask: &field_mask.FieldMask{ - Paths: []string{"labels"}, - }, - } - - _, err := s.Client.UpdateNamespace(ctx, req) - if err == nil { - return ns, nil - } - - return nil, castStatusToErr(err) -} - -// DeleteNs deletes the namespace. -func (s *Handler) DeleteNs(name string) error { - // -- Init - if err := s.checkNames(&name, nil, nil); err != nil { - return err - } - - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - req := &sdpb.DeleteNamespaceRequest{ - Name: s.getResourcePath(servDirPath{namespace: name}), - } - - err := s.Client.DeleteNamespace(ctx, req) - if err == nil { - return nil - } - - return castStatusToErr(err) -} diff --git a/pkg/servregistry/gcloud/servicedirectory/namespace_test.go b/pkg/servregistry/gcloud/servicedirectory/namespace_test.go deleted file mode 100644 index 11c0a48..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/namespace_test.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servicedirectory - -import ( - "testing" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - a "github.com/stretchr/testify/assert" -) - -func TestGetNs(t *testing.T) { - s := getFakeHandler() - nsName := "ns" - - // Test errors on service directory - testErr := func(tt *testing.T) { - assert := a.New(tt) - - regNs, err := s.GetNs("get-error") - assert.Nil(regNs) - assert.Error(err) - assert.NotEqual(sr.ErrTimeOutExpired, err) - assert.NotEqual(sr.ErrNotFound, err) - - regNs, err = s.GetNs("timeout-error") - assert.Nil(regNs) - assert.Equal(sr.ErrTimeOutExpired, err) - - regNs, err = s.GetNs("get-not-found") - assert.Nil(regNs) - assert.Equal(sr.ErrNotFound, err) - } - - // Test success on service directory - testOk := func(tt *testing.T) { - assert := a.New(tt) - - regNs, err := s.GetNs(nsName) - assert.NotNil(regNs) - assert.NoError(err) - assert.NotContains(regNs.Name, "/") - } - - testErr(t) - testOk(t) -} - -func TestCreateNs(t *testing.T) { - s := getFakeHandler() - ns := &sr.Namespace{} - nsName := "ns" - - // Test errors on service directory - testErr := func(tt *testing.T) { - assert := a.New(tt) - - ns.Name = "create-error" - regNs, err := s.CreateNs(ns) - assert.Nil(regNs) - assert.Error(err) - assert.NotEqual(sr.ErrTimeOutExpired, err) - assert.NotEqual(sr.ErrNotFound, err) - - ns.Name = "timeout-error" - regNs, err = s.CreateNs(ns) - assert.Nil(regNs) - assert.Equal(sr.ErrTimeOutExpired, err) - - ns.Name = "create-exists" - regNs, err = s.CreateNs(ns) - assert.Nil(regNs) - assert.Equal(sr.ErrAlreadyExists, err) - } - - // Test success on service directory - testOk := func(tt *testing.T) { - assert := a.New(tt) - - ns.Name = nsName - regNs, err := s.CreateNs(ns) - assert.NotNil(regNs) - assert.NoError(err) - assert.NotContains(regNs.Name, "/") - } - - testErr(t) - testOk(t) -} - -func TestUpdateNs(t *testing.T) { - s := getFakeHandler() - ns := &sr.Namespace{} - nsName := "ns" - - // Test errors on service directory - testErr := func(tt *testing.T) { - assert := a.New(tt) - - ns.Name = "update-error" - regNs, err := s.UpdateNs(ns) - assert.Nil(regNs) - assert.Error(err) - assert.NotEqual(sr.ErrTimeOutExpired, err) - assert.NotEqual(sr.ErrNotFound, err) - - ns.Name = "timeout-error" - regNs, err = s.UpdateNs(ns) - assert.Nil(regNs) - assert.Equal(sr.ErrTimeOutExpired, err) - - ns.Name = "update-not-found" - regNs, err = s.UpdateNs(ns) - assert.Nil(regNs) - assert.Equal(sr.ErrNotFound, err) - } - - // Test success on service directory - testOk := func(tt *testing.T) { - assert := a.New(tt) - - ns.Name = nsName - regNs, err := s.UpdateNs(ns) - assert.NotNil(regNs) - assert.NoError(err) - assert.NotContains(regNs.Name, "/") - } - - testErr(t) - testOk(t) -} - -func TestDeleteNs(t *testing.T) { - s := getFakeHandler() - nsName := "ns" - - // Test errors on service directory - testErr := func(tt *testing.T) { - assert := a.New(tt) - - err := s.DeleteNs("delete-error") - assert.Error(err) - assert.NotEqual(sr.ErrTimeOutExpired, err) - assert.NotEqual(sr.ErrNotFound, err) - - err = s.DeleteNs("timeout-error") - assert.Equal(sr.ErrTimeOutExpired, err) - - err = s.DeleteNs("delete-not-found") - assert.Equal(sr.ErrNotFound, err) - } - - // Test success on service directory - testOk := func(tt *testing.T) { - assert := a.New(tt) - - err := s.DeleteNs(nsName) - assert.NoError(err) - } - - testErr(t) - testOk(t) -} - -func TestListNs(t *testing.T) { - // Not tested as currently not used by the operator -} diff --git a/pkg/servregistry/gcloud/servicedirectory/registration_client_interface.go b/pkg/servregistry/gcloud/servicedirectory/registration_client_interface.go deleted file mode 100644 index d78ae3c..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/registration_client_interface.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servicedirectory - -import ( - "context" - - sd "cloud.google.com/go/servicedirectory/apiv1" - "github.com/googleapis/gax-go/v2" - sdpb "google.golang.org/genproto/googleapis/cloud/servicedirectory/v1" - iampb "google.golang.org/genproto/googleapis/iam/v1" -) - -type regClient interface { - Close() error - CreateEndpoint(ctx context.Context, req *sdpb.CreateEndpointRequest, opts ...gax.CallOption) (*sdpb.Endpoint, error) - CreateNamespace(ctx context.Context, req *sdpb.CreateNamespaceRequest, opts ...gax.CallOption) (*sdpb.Namespace, error) - CreateService(ctx context.Context, req *sdpb.CreateServiceRequest, opts ...gax.CallOption) (*sdpb.Service, error) - DeleteEndpoint(ctx context.Context, req *sdpb.DeleteEndpointRequest, opts ...gax.CallOption) error - DeleteNamespace(ctx context.Context, req *sdpb.DeleteNamespaceRequest, opts ...gax.CallOption) error - DeleteService(ctx context.Context, req *sdpb.DeleteServiceRequest, opts ...gax.CallOption) error - GetEndpoint(ctx context.Context, req *sdpb.GetEndpointRequest, opts ...gax.CallOption) (*sdpb.Endpoint, error) - GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) - GetNamespace(ctx context.Context, req *sdpb.GetNamespaceRequest, opts ...gax.CallOption) (*sdpb.Namespace, error) - GetService(ctx context.Context, req *sdpb.GetServiceRequest, opts ...gax.CallOption) (*sdpb.Service, error) - ListEndpoints(ctx context.Context, req *sdpb.ListEndpointsRequest, opts ...gax.CallOption) *sd.EndpointIterator - ListNamespaces(ctx context.Context, req *sdpb.ListNamespacesRequest, opts ...gax.CallOption) *sd.NamespaceIterator - ListServices(ctx context.Context, req *sdpb.ListServicesRequest, opts ...gax.CallOption) *sd.ServiceIterator - SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) - TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) - UpdateEndpoint(ctx context.Context, req *sdpb.UpdateEndpointRequest, opts ...gax.CallOption) (*sdpb.Endpoint, error) - UpdateNamespace(ctx context.Context, req *sdpb.UpdateNamespaceRequest, opts ...gax.CallOption) (*sdpb.Namespace, error) - UpdateService(ctx context.Context, req *sdpb.UpdateServiceRequest, opts ...gax.CallOption) (*sdpb.Service, error) -} diff --git a/pkg/servregistry/gcloud/servicedirectory/service.go b/pkg/servregistry/gcloud/servicedirectory/service.go deleted file mode 100644 index e9e8532..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/service.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright © 2020, 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servicedirectory - -import ( - "context" - "strings" - "time" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "google.golang.org/api/iterator" - sdpb "google.golang.org/genproto/googleapis/cloud/servicedirectory/v1" - "google.golang.org/genproto/protobuf/field_mask" -) - -// GetServ returns the service if exists. -func (s *Handler) GetServ(nsName, servName string) (*sr.Service, error) { - // -- Init - if err := s.checkNames(&nsName, &servName, nil); err != nil { - return nil, err - } - - servPath := s.getResourcePath(servDirPath{namespace: nsName, service: servName}) - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - sdServ, err := s.Client.GetService(ctx, &sdpb.GetServiceRequest{Name: servPath}) - if err == nil { - serv := &sr.Service{ - Name: servName, - NsName: nsName, - Metadata: sdServ.Annotations, - } - if serv.Metadata == nil { - serv.Metadata = map[string]string{} - } - - return serv, nil - } - - return nil, castStatusToErr(err) -} - -// ListServ returns a list of services inside the provided namespace. -func (s *Handler) ListServ(nsName string) (servList []*sr.Service, err error) { - // -- Init - if err := s.checkNames(&nsName, nil, nil); err != nil { - return nil, err - } - l := s.Log.WithName("ListServ").WithValues("ns-name", nsName) - ctx, canc := context.WithTimeout(s.Context, time.Minute) - defer canc() - - req := &sdpb.ListServicesRequest{ - Parent: s.getResourcePath(servDirPath{namespace: nsName}), - } - - iter := s.Client.ListServices(ctx, req) - if iter == nil { - l.V(0).Info("returned list is nil") - return - } - for { - nextServ, iterErr := iter.Next() - if iterErr != nil { - - if iterErr == context.DeadlineExceeded { - l.Error(err, "timeout expired while waiting for service directory to reply", "timeout-seconds", defTimeout.Seconds()) - return nil, sr.ErrTimeOutExpired - } - - if iterErr != iterator.Done { - l.Error(iterErr, "error while loading services") - return nil, iterErr - } - - break - } - - // Create the list - splitName := strings.Split(nextServ.Name, "/") - serv := &sr.Service{ - Name: splitName[len(splitName)-1], - NsName: nsName, - Metadata: nextServ.Annotations, - } - if serv.Metadata == nil { - serv.Metadata = map[string]string{} - } - - servList = append(servList, serv) - } - - return -} - -// CreateServ creates the service. -func (s *Handler) CreateServ(serv *sr.Service) (*sr.Service, error) { - // -- Init - if serv == nil { - return nil, sr.ErrServNotProvided - } - if err := s.checkNames(&serv.NsName, &serv.Name, nil); err != nil { - return nil, err - } - - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - servToCreate := &sdpb.Service{ - Name: serv.Name, - Annotations: serv.Metadata, - } - - req := &sdpb.CreateServiceRequest{ - Parent: s.getResourcePath(servDirPath{namespace: serv.NsName}), - ServiceId: serv.Name, - Service: servToCreate, - } - - _, err := s.Client.CreateService(ctx, req) - if err == nil { - // If it is successful, then it makes no point in parsing the returned - // service from service directory, because it will look like just the - // same as the service we want to create, apart from having prefixes - // in the name, which is something we want to abstract to someone - // using this. - return serv, nil - } - - return nil, castStatusToErr(err) -} - -// UpdateServ updates the service. -func (s *Handler) UpdateServ(serv *sr.Service) (*sr.Service, error) { - // -- Init - if serv == nil { - return nil, sr.ErrServNotProvided - } - if err := s.checkNames(&serv.NsName, &serv.Name, nil); err != nil { - return nil, err - } - - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - servToUpd := &sdpb.Service{ - Name: s.getResourcePath(servDirPath{namespace: serv.NsName, service: serv.Name}), - Annotations: serv.Metadata, - } - - req := &sdpb.UpdateServiceRequest{ - Service: servToUpd, - UpdateMask: &field_mask.FieldMask{ - Paths: []string{"annotations"}, - }, - } - - _, err := s.Client.UpdateService(ctx, req) - if err == nil { - return serv, nil - } - - return nil, castStatusToErr(err) -} - -// DeleteServ deletes the service. -func (s *Handler) DeleteServ(nsName, servName string) error { - // -- Init - if err := s.checkNames(&nsName, &servName, nil); err != nil { - return err - } - - ctx, canc := context.WithTimeout(s.Context, defTimeout) - defer canc() - - req := &sdpb.DeleteServiceRequest{ - Name: s.getResourcePath(servDirPath{namespace: nsName, service: servName}), - } - - err := s.Client.DeleteService(ctx, req) - if err == nil { - return nil - } - - return castStatusToErr(err) -} diff --git a/pkg/servregistry/gcloud/servicedirectory/service_directory_handler.go b/pkg/servregistry/gcloud/servicedirectory/service_directory_handler.go deleted file mode 100644 index a9dd4cc..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/service_directory_handler.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright © 2020, 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servicedirectory - -import ( - "context" - "crypto/sha256" - "fmt" - "time" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" -) - -const ( - defTimeout time.Duration = 30 * time.Second -) - -// Handler is a wrapper for Service Directory that exposes its methods in a -// sort of "universal" way through the ServiceRegistry interface. -type Handler struct { - // ProjectID where ServiceDirectory is enabled. - ProjectID string - // DefaultRegion where namespaces, services and endpoints are going to be - // registered to. - DefaultRegion string - // Log to use. - Log logr.Logger - // Context to use for requests. - // TODO: remove this in favor of explicit context for each call? - Context context.Context - // Client to wrap around. - Client regClient -} - -func (s *Handler) ExtractData(ns *corev1.Namespace, serv *corev1.Service) (namespaceData *sr.Namespace, serviceData *sr.Service, endpointsData []*sr.Endpoint, err error) { - if ns == nil { - err = sr.ErrNsNotProvided - return - } - if serv == nil { - err = sr.ErrServNotProvided - return - } - - // Parse the namespace - namespaceData = &sr.Namespace{ - Name: ns.Name, - Metadata: ns.Annotations, - } - if namespaceData.Metadata == nil { - namespaceData.Metadata = map[string]string{} - } - - // Parse the service - // NOTE: we put metadata on the service in service directory, - // not on the endpoints - serviceData = &sr.Service{ - Name: serv.Name, - NsName: ns.Name, - Metadata: serv.Annotations, - } - if serviceData.Metadata == nil { - serviceData.Metadata = map[string]string{} - } - - // Get the endpoints from the service - // First, build the ips - ips := []string{} - ips = append(ips, serv.Spec.ExternalIPs...) - - // Get data from load balancers - for _, ing := range serv.Status.LoadBalancer.Ingress { - ips = append(ips, ing.IP) - } - - for _, port := range serv.Spec.Ports { - for _, ip := range ips { - - // Create an hashed name for this - toBeHashed := fmt.Sprintf("%s-%d", ip, port.Port) - h := sha256.New() - h.Write([]byte(toBeHashed)) - hash := fmt.Sprintf("%x", h.Sum(nil)) - - // Only take the first 10 characters of the hashed name - name := fmt.Sprintf("%s-%s", serv.Name, hash[:10]) - endpointsData = append(endpointsData, &sr.Endpoint{ - Name: name, - NsName: namespaceData.Name, - ServName: serviceData.Name, - Address: ip, - Port: port.Port, - Metadata: map[string]string{}, - }) - } - } - - return -} diff --git a/pkg/servregistry/gcloud/servicedirectory/service_directory_handler_test.go b/pkg/servregistry/gcloud/servicedirectory/service_directory_handler_test.go deleted file mode 100644 index 3ba9ce9..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/service_directory_handler_test.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright © 2020, 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servicedirectory - -import ( - "strings" - "testing" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - a "github.com/stretchr/testify/assert" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestExtractData(t *testing.T) { - nsName, servName := "ns", "serv" - s := &Handler{} - ips := []string{"10.10.10.10", "11.11.11.11"} - ports := []int32{3333, 4444} - nsToTest := &corev1.Namespace{ - ObjectMeta: v1.ObjectMeta{ - Name: nsName, - Annotations: map[string]string{ - "key": "val", - }, - }, - } - servToTest := &corev1.Service{ - ObjectMeta: v1.ObjectMeta{ - Name: servName, - Namespace: nsName, - Annotations: map[string]string{ - "key": "val", - }, - }, - Spec: corev1.ServiceSpec{ - ExternalIPs: []string{ips[0], ips[1]}, - Ports: []corev1.ServicePort{ - { - Port: ports[0], - Name: "3333", - }, - { - Port: ports[1], - Name: "4444", - }, - }, - }, - } - - assert := a.New(t) - - ns, serv, endp, err := s.ExtractData(nsToTest, nil) - assert.Nil(ns) - assert.Nil(serv) - assert.Nil(endp) - assert.Equal(sr.ErrServNotProvided, err) - - ns, serv, endp, err = s.ExtractData(nil, servToTest) - assert.Nil(ns) - assert.Nil(serv) - assert.Nil(endp) - assert.Equal(sr.ErrNsNotProvided, err) - - ns, serv, endp, err = s.ExtractData(nsToTest, servToTest) - assert.NotNil(ns) - assert.NotNil(serv) - assert.NotNil(endp) - assert.NoError(err) - assert.Equal(&sr.Namespace{ - Name: nsName, - Metadata: nsToTest.Annotations, - }, ns) - assert.Equal(&sr.Service{ - Name: servName, - NsName: nsName, - Metadata: servToTest.Annotations, - }, serv) - assert.Len(endp, 4) - for _, e := range endp { - assert.Contains(ips, e.Address) - assert.Contains(ports, e.Port) - assert.Empty(e.Metadata) - assert.Equal(nsName, e.NsName) - assert.Equal(servName, e.ServName) - - if !strings.HasPrefix(e.Name, servName+"-") { - assert.Fail("endpoint name is incorrect. Should start with", servName, "but is", e.Name) - } - - suffix := e.Name[len(servName)+1:] - assert.Len(suffix, 10) - } -} diff --git a/pkg/servregistry/gcloud/servicedirectory/service_test.go b/pkg/servregistry/gcloud/servicedirectory/service_test.go deleted file mode 100644 index b1b8949..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/service_test.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servicedirectory - -import ( - "testing" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - a "github.com/stretchr/testify/assert" -) - -func TestGetServ(t *testing.T) { - s := getFakeHandler() - nsName, servName := "ns", "serv" - - // Test errors - testErr := func(tt *testing.T) { - assert := a.New(tt) - - regServ, err := s.GetServ(nsName, "get-error") - assert.Nil(regServ) - assert.Error(err) - assert.NotEqual(sr.ErrTimeOutExpired, err) - assert.NotEqual(sr.ErrNotFound, err) - - regServ, err = s.GetServ(nsName, "timeout-error") - assert.Nil(regServ) - assert.Equal(sr.ErrTimeOutExpired, err) - - regServ, err = s.GetServ(nsName, "get-not-found") - assert.Nil(regServ) - assert.Equal(sr.ErrNotFound, err) - } - - // Test success on service directory - testOk := func(tt *testing.T) { - assert := a.New(tt) - - regServ, err := s.GetServ(nsName, servName) - assert.NotNil(regServ) - assert.NoError(err) - assert.NotContains(regServ.Name, "/") - assert.Equal(regServ.NsName, nsName) - } - - testErr(t) - testOk(t) -} - -func TestCreateServ(t *testing.T) { - s := getFakeHandler() - nsName, servName := "ns", "serv" - req := &sr.Service{NsName: nsName} - - // Test errors on service directory - testErr := func(tt *testing.T) { - assert := a.New(tt) - - regServ, err := s.CreateServ(nil) - assert.Nil(regServ) - assert.Equal(sr.ErrServNotProvided, err) - - req.Name = "create-error" - regServ, err = s.CreateServ(req) - assert.Nil(regServ) - assert.Error(err) - assert.NotEqual(sr.ErrTimeOutExpired, err) - assert.NotEqual(sr.ErrNotFound, err) - - req.Name = "timeout-error" - regServ, err = s.CreateServ(req) - assert.Nil(regServ) - assert.Equal(sr.ErrTimeOutExpired, err) - - req.Name = "create-exists" - regServ, err = s.CreateServ(req) - assert.Nil(regServ) - assert.Equal(sr.ErrAlreadyExists, err) - } - - // Test success on service directory - testOk := func(tt *testing.T) { - assert := a.New(tt) - - req.Name = servName - regServ, err := s.CreateServ(req) - assert.NotNil(regServ) - assert.NoError(err) - assert.NotContains(regServ.Name, "/") - assert.Equal(regServ.NsName, nsName) - } - - testErr(t) - testOk(t) -} - -func TestUpdateServ(t *testing.T) { - s := getFakeHandler() - nsName, servName := "ns", "serv" - req := &sr.Service{NsName: nsName} - - // Test errors on service directory - testErr := func(tt *testing.T) { - assert := a.New(tt) - - regServ, err := s.UpdateServ(nil) - assert.Nil(regServ) - assert.Equal(sr.ErrServNotProvided, err) - - req.Name = "update-error" - regServ, err = s.UpdateServ(req) - assert.Nil(regServ) - assert.Error(err) - assert.NotEqual(sr.ErrTimeOutExpired, err) - assert.NotEqual(sr.ErrNotFound, err) - - req.Name = "timeout-error" - regServ, err = s.UpdateServ(req) - assert.Nil(regServ) - assert.Equal(sr.ErrTimeOutExpired, err) - - req.Name = "update-not-found" - regServ, err = s.UpdateServ(req) - assert.Nil(regServ) - assert.Equal(sr.ErrNotFound, err) - } - - // Test success on service directory - testOk := func(tt *testing.T) { - assert := a.New(tt) - - req.Name = servName - regServ, err := s.UpdateServ(req) - assert.NotNil(regServ) - assert.NoError(err) - assert.NotContains(regServ.Name, "/") - assert.Equal(regServ.NsName, nsName) - } - - testErr(t) - testOk(t) -} - -func TestDeleteServ(t *testing.T) { - s := getFakeHandler() - nsName, servName := "ns", "serv" - - // Test errors on service directory - testErr := func(tt *testing.T) { - assert := a.New(tt) - - err := s.DeleteServ(nsName, "delete-error") - assert.Error(err) - assert.NotEqual(sr.ErrTimeOutExpired, err) - assert.NotEqual(sr.ErrNotFound, err) - - err = s.DeleteServ(nsName, "timeout-error") - assert.Equal(sr.ErrTimeOutExpired, err) - - err = s.DeleteServ(nsName, "delete-not-found") - assert.Equal(sr.ErrNotFound, err) - } - - // Test success on service directory - testOk := func(tt *testing.T) { - assert := a.New(tt) - - err := s.DeleteServ(nsName, servName) - assert.NoError(err) - } - - testErr(t) - testOk(t) -} diff --git a/pkg/servregistry/gcloud/servicedirectory/utils.go b/pkg/servregistry/gcloud/servicedirectory/utils.go deleted file mode 100644 index c355fcb..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/utils.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright © 2020, 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servicedirectory - -import ( - "path" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -type servDirPath struct { - project string - region string - namespace string - service string - endpoint string -} - -func (s *Handler) getResourcePath(res servDirPath) string { - resource := "" - - proj := res.project - if len(proj) == 0 { - proj = s.ProjectID - } - resource = path.Join("projects", proj) - - loc := res.region - if len(loc) == 0 { - loc = s.DefaultRegion - } - resource = path.Join(resource, "locations", loc) - - if len(res.namespace) > 0 { - resource = path.Join(resource, "namespaces", res.namespace) - - if len(res.service) > 0 { - resource = path.Join(resource, "services", res.service) - - if len(res.endpoint) > 0 { - resource = path.Join(resource, "endpoints", res.endpoint) - } - } - } - - return resource -} - -func (s *Handler) checkNames(nsName, servName, endpName *string) error { - if nsName != nil && len(*nsName) == 0 { - return sr.ErrNsNameNotProvided - } - if servName != nil && len(*servName) == 0 { - return sr.ErrServNameNotProvided - } - if endpName != nil && len(*endpName) == 0 { - return sr.ErrEndpNameNotProvided - } - - return nil -} - -func castStatusToErr(err error) error { - // What is the error? - switch status.Code(err) { - case codes.DeadlineExceeded: - return sr.ErrTimeOutExpired - case codes.AlreadyExists: - return sr.ErrAlreadyExists - case codes.NotFound: - return sr.ErrNotFound - default: - return err - } -} diff --git a/pkg/servregistry/gcloud/servicedirectory/utils_test.go b/pkg/servregistry/gcloud/servicedirectory/utils_test.go deleted file mode 100644 index 31ef59f..0000000 --- a/pkg/servregistry/gcloud/servicedirectory/utils_test.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright © 2020, 2021 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servicedirectory - -import ( - "testing" - - sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry" - a "github.com/stretchr/testify/assert" -) - -func TestGetResourcePath(t *testing.T) { - s := &Handler{ProjectID: "project", DefaultRegion: "us"} - assert := a.New(t) - - // Test no project/region provided - res := s.getResourcePath(servDirPath{}) - assert.Equal("projects/project/locations/us", res) - - // Test project provided - arg := servDirPath{ - project: "other-project", - } - res = s.getResourcePath(arg) - assert.Equal("projects/other-project/locations/us", res) - - // Test loaction provided - arg.region = "asia" - res = s.getResourcePath(arg) - assert.Equal("projects/other-project/locations/asia", res) - - // Test service cannot exist with namespace provided - arg.service = "serv" - res = s.getResourcePath(arg) - assert.Equal("projects/other-project/locations/asia", res) - arg.service = "" - - // Test ns provided - arg.namespace = "ns" - res = s.getResourcePath(arg) - assert.Equal("projects/other-project/locations/asia/namespaces/ns", res) - - // Test endpoint cannot live without service - arg.endpoint = "endp" - res = s.getResourcePath(arg) - assert.Equal("projects/other-project/locations/asia/namespaces/ns", res) - arg.endpoint = "" - - // Test service provided - arg.service = "serv" - res = s.getResourcePath(arg) - assert.Equal("projects/other-project/locations/asia/namespaces/ns/services/serv", res) - - // Test endpoint provided - arg.endpoint = "endp" - res = s.getResourcePath(arg) - assert.Equal("projects/other-project/locations/asia/namespaces/ns/services/serv/endpoints/endp", res) -} - -func TestCheckNames(t *testing.T) { - s := getFakeHandler() - assert := a.New(t) - - err := s.checkNames(nil, nil, nil) - assert.NoError(err) - - nsName := "" - err = s.checkNames(&nsName, nil, nil) - assert.Equal(sr.ErrNsNameNotProvided, err) - - nsName = "ns" - servName := "" - err = s.checkNames(&nsName, &servName, nil) - assert.Equal(sr.ErrServNameNotProvided, err) - - servName = "serv" - endpName := "" - err = s.checkNames(&nsName, &servName, &endpName) - assert.Equal(sr.ErrEndpNameNotProvided, err) - - endpName = "endp" - err = s.checkNames(&nsName, &servName, &endpName) - assert.NoError(err) -} diff --git a/pkg/servregistry/namespace.go b/pkg/servregistry/namespace.go deleted file mode 100644 index ca969e5..0000000 --- a/pkg/servregistry/namespace.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servregistry - -// This file contains functions that perform operations on namespaces, -// such as create/update/delete. -// These functions belong to a ServiceRegistryBroker, defined in -// broker.go - -// ManageNs takes data of a namespace and performs the necessary steps -// to reflect that data to the service registry. -// -// For example: create a namespace in service registry or update it -// properly. -func (b *Broker) ManageNs(nsData *Namespace) (regNs *Namespace, err error) { - // nsData: data of the namespace in Kubernetes (latest state) - // regNs: data of the namespace currently in the service registry - - if b.Reg == nil { - return nil, ErrServRegNotProvided - } - - // -- Validate - if nsData == nil { - return nil, ErrNsNotProvided - } - - if len(nsData.Name) == 0 { - return nil, ErrNsNameNotProvided - } - - // -- Init - b.lock.Lock() - defer b.lock.Unlock() - if nsData.Metadata == nil { - nsData.Metadata = map[string]string{} - } - nsData.Metadata[b.opMetaPair.Key] = b.opMetaPair.Value - l := b.log.WithName("ManageNs").WithValues("ns-name", nsData.Name) - - // -- Do stuff - l.V(1).Info("going to load namespace from service registry") - - regNs, err = b.Reg.GetNs(nsData.Name) - if err != nil { - if err != ErrNotFound { - l.Error(err, "error occurred while getting namespace from service registry") - return - } - - // If you're here, it means that the namespace does not exist. - // Let's create it. - l.V(1).Info("namespace does not exist in service registry, going to create it") - regNs, err = b.Reg.CreateNs(nsData) - if err != nil { - l.Error(err, "error occurred while creating namespace in service registry") - return - } - - l.V(0).Info("namespace created correctly") - regNs = nsData - } - - if by, exists := regNs.Metadata[b.opMetaPair.Key]; by != b.opMetaPair.Value || !exists { - // If the namespace is not owned (as in, managed by) us, then it's - // better not to touch it. - l.V(0).Info("namespace is not owned by the operator and thus will not be updated") - return - } - - if !b.deepEqualMetadata(nsData.Metadata, regNs.Metadata) { - l.V(1).Info("namespace metadata need to be updated") - regNs, err = b.Reg.UpdateNs(nsData) - if err != nil { - l.Error(err, "error while trying to update namespace in service registry") - return nil, err - } - } - - return -} - -// RemoveNs checks if a namespace can be safely deleted from the -// service registry before actually delete it. The second parameter forces -// the function to delete the namespace even if it is not empty. -// NOTE: setting forceNotEmpty to true will have no effect if the namespace -// contains services not owned by the operator, and therefore the namespace -// will not be deleted. -// NOTE: this function does *not* check if one of the contained services has -// endpoints not owned by the cnwan operator! -// -// For example: it checks if the namespace is actually owned by us. -func (b *Broker) RemoveNs(nsName string, forceNotEmpty bool) (err error) { - if b.Reg == nil { - return ErrServRegNotProvided - } - - // -- Validate - if len(nsName) == 0 { - return ErrNsNameNotProvided - } - - // -- Init - b.lock.Lock() - defer b.lock.Unlock() - l := b.log.WithName("RemoveNs").WithValues("ns-name", nsName) - - // -- Do stuff - l.V(1).Info("going to remove namespace from service registry") - - // Load the namespace first - regNs, err := b.Reg.GetNs(nsName) - if err != nil { - if err != ErrNotFound { - l.Error(err, "error occurred while removing namespace from service registry") - return - } - - // If you're here, it means that the namespace does not exist. - // This doesn't change anything for us. - l.V(0).Info("namespace does not exist in service registry, going to stop here") - return nil - } - - // Is it empty? - l.V(1).Info("checking if namespace is empty before deleting") - listServ, err := b.Reg.ListServ(nsName) - if err != nil { - return - } - - if len(listServ) > 0 && !forceNotEmpty { - l.V(0).Info("namespace is not empty and will not be deleted from service registry") - return ErrNsNotEmpty - } - - l.V(0).Info("namespace is not empty: checking if it can be removed") - servs := []string{} - hasNotOwned := false - for _, serv := range listServ { - if by, exists := serv.Metadata[b.opMetaPair.Key]; by != b.opMetaPair.Value || !exists { - l.V(0).Info("namespace contains services not owned by the operator") - hasNotOwned = true - continue - } - - servs = append(servs, serv.Name) - } - - if hasNotOwned { - // There are some services not owned by the operator, so we must delete - // services singularly - l.V(0).Info("namespace contains services not owned by the operator and will not be removed from service registry") - for _, servName := range servs { - if delErr := b.Reg.DeleteServ(nsName, servName); delErr != nil { - l.WithValues("serv-name", servName).Error(delErr, "error while deleting service from service registry") - } - } - - return ErrNsNotOwnedServs - } - - if by, exists := regNs.Metadata[b.opMetaPair.Key]; by != b.opMetaPair.Value || !exists { - // If the namespace is not owned (as in, managed by) us, then it's - // better not to touch it. - l.V(0).Info("WARNING: namespace is not owned by the operator and will not be removed from service registry") - return ErrNsNotOwnedByOp - } - - err = b.Reg.DeleteNs(nsName) - if err != nil { - l.Error(err, "error while deleting namespace from service registry") - } - - l.V(0).Info("namespace deleted from service registry successfully") - return -} diff --git a/pkg/servregistry/namespace_test.go b/pkg/servregistry/namespace_test.go deleted file mode 100644 index f998475..0000000 --- a/pkg/servregistry/namespace_test.go +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servregistry - -import ( - "testing" - - a "github.com/stretchr/testify/assert" -) - -func TestManageNs(t *testing.T) { - // prepare - var f *fakeServReg - b, _ := NewBroker(f, MetadataPair{}) - - resetFake := func() { - f = newFakeStruct() - b.Reg = f - } - - resetFake() - - // Test validation - testValidation := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - invalidNsData := &Namespace{} - regNs := &Namespace{} - var err error - - // no service registry provided - b.Reg = nil - regNs, err = b.ManageNs(nil) - assert.Nil(regNs) - assert.Equal(ErrServRegNotProvided, err) - - // namespace is nil - b.Reg = f - regNs, err = b.ManageNs(nil) - assert.Nil(regNs) - assert.Equal(ErrNsNotProvided, err) - - // namespace has no name - regNs, err = b.ManageNs(invalidNsData) - assert.Nil(regNs) - assert.Equal(ErrNsNameNotProvided, err) - - assert.Empty(f.createdNs) - assert.Empty(f.updatedNs) - } - - // Test returns nil when an unknown error is thrown by the service registry - testUnErr := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - regNs, err := b.ManageNs(&Namespace{Name: "get-error"}) - assert.Nil(regNs) - assert.Error(err) - assert.NotEqual(ErrNsNameNotProvided, err) - assert.NotEqual(ErrNsNotProvided, err) - assert.NotEqual(ErrNsNameNotProvided, err) - - assert.Empty(f.createdNs) - assert.Empty(f.updatedNs) - } - - // Test namespaces not owned by the operator are not modified - testNotOwned := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - one := &Namespace{Name: "one", Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}} - two := &Namespace{Name: "two", Metadata: map[string]string{"key": "val"}} - - oneChange := &Namespace{Name: "one", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} - twoChange := &Namespace{Name: "two", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} - f.nsList[one.Name] = one - f.nsList[two.Name] = two - - regNs, err := b.ManageNs(oneChange) - assert.Equal(one, regNs) - assert.NoError(err) - - regNs, err = b.ManageNs(twoChange) - assert.Equal(two, regNs) - assert.NoError(err) - - assert.Empty(f.createdNs) - assert.Empty(f.updatedNs) - } - - // Test namespaces owned by the operator are modified - testOwned := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - // should return nil because an error in updating - shouldErr := &Namespace{Name: "update-error", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - changeErr := &Namespace{Name: "update-error", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} - f.nsList[shouldErr.Name] = shouldErr - - regNs, err := b.ManageNs(changeErr) - assert.Nil(regNs) - assert.Error(err) - - // no error so it should return the new value - shouldOk := &Namespace{Name: "update", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - changeOk := &Namespace{Name: "update", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} - f.nsList[shouldOk.Name] = shouldOk - - regNs, err = b.ManageNs(changeOk) - assert.Equal(changeOk, regNs) - assert.NoError(err) - - assert.Empty(f.createdNs) - } - - // Test namespaces are created if they do not exist - testCreate := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - // should return nil because an error in creating - // (this also happens if someone else creates this) - create := &Namespace{Name: "create-error", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - regNs, err := b.ManageNs(create) - assert.Nil(regNs) - assert.Error(err) - - // no error so it should return the created - create = &Namespace{Name: "create", Metadata: map[string]string{"key": "val"}} - regNs, err = b.ManageNs(create) - assert.Equal(create.Name, regNs.Name) - assert.Equal(map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, regNs.Metadata) - assert.NoError(err) - - assert.Empty(f.updatedNs) - } - - testValidation(t) - testUnErr(t) - testNotOwned(t) - testOwned(t) - testCreate(t) -} - -func TestRemoveNs(t *testing.T) { - // prepare - nsName := "ns" - var f *fakeServReg - b, _ := NewBroker(f, MetadataPair{}) - - resetFake := func() { - f = newFakeStruct() - b.Reg = f - } - - resetFake() - - // Test validation - testValidation := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - // no service registry provided - b.Reg = nil - err := b.RemoveNs(nsName, false) - assert.Equal(ErrServRegNotProvided, err) - - // namespace name not provided - b.Reg = f - err = b.RemoveNs("", false) - assert.Equal(ErrNsNameNotProvided, err) - assert.Empty(f.deletedNs) - } - - // Test returns nil when an unknown error is thrown by the service registry - testUnErr := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - err := b.RemoveNs("get-error", false) - assert.Error(err) - assert.NotEqual(ErrNsNameNotProvided, err) - assert.NotEqual(ErrNsNotProvided, err) - assert.NotEqual(ErrNsNameNotProvided, err) - - assert.Empty(f.deletedNs) - } - - // Test namespaces not owned by the operator are not deleted - testNotOwned := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - one := &Namespace{Name: "not-owned", Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}} - two := &Namespace{Name: "not-owned", Metadata: map[string]string{"key": "val"}} - f.nsList[one.Name] = one - f.nsList[two.Name] = two - - err := b.RemoveNs(one.Name, false) - assert.Equal(ErrNsNotOwnedByOp, err) - - err = b.RemoveNs(two.Name, false) - assert.Equal(ErrNsNotOwnedByOp, err) - assert.Empty(f.deletedNs) - } - - // Test empty owned namespaces are deleted - testEmptyOwned := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - // when it doesn't exist, we just log but return no error - // because it doesn't change anything for us - err := b.RemoveNs("doesnt-exist", false) - assert.NoError(err) - - // unknown error - toDel := &Namespace{Name: "delete-error", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - f.nsList[toDel.Name] = toDel - err = b.RemoveNs("delete-error", false) - assert.NotEqual(ErrServRegNotProvided, err) - assert.NotEqual(ErrNsNameNotProvided, err) - - // successful - present := &Namespace{Name: "owned", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - f.nsList[present.Name] = present - err = b.RemoveNs("owned", false) - assert.NoError(err) - assert.Len(f.deletedNs, 1) - } - - // Test not empty owned namespaces are deleted/not deleted - testNotEmptyOwned := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - oneOwned := &Service{ - Name: "one", - Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, - NsName: nsName, - } - twoOwned := &Service{ - Name: "two", - Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, - NsName: nsName, - } - threeNotOwned := &Service{ - Name: "three", - Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}, - NsName: nsName, - } - nsDel := &Namespace{Name: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - f.nsList[nsDel.Name] = nsDel - - // error in listing - f.servList["list-error"] = &Service{} - err := b.RemoveNs(nsDel.Name, false) - assert.Error(err) - delete(f.servList, "list-error") - - // there is a service not owned by us - f.servList["one"] = oneOwned - f.servList["two"] = twoOwned - f.servList["three"] = threeNotOwned - err = b.RemoveNs(nsDel.Name, false) - assert.Empty(f.deletedServ) - assert.Empty(f.deletedNs) - assert.Equal(ErrNsNotEmpty, err) - - err = b.RemoveNs(nsDel.Name, true) - assert.Len(f.deletedServ, 2) - assert.Empty(f.deletedNs) - assert.Equal(ErrNsNotOwnedServs, err) - assert.Contains(f.deletedServ, oneOwned.Name) - assert.Contains(f.deletedServ, twoOwned.Name) - - // error occurs in deleting namespace - shouldErr := &Namespace{Name: "delete-error", Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - f.nsList[shouldErr.Name] = shouldErr - f.deletedServ = []string{} - f.deletedNs = []string{} - err = b.RemoveNs(shouldErr.Name, true) - assert.Error(err) - } - - testValidation(t) - testUnErr(t) - testNotOwned(t) - testEmptyOwned(t) - testNotEmptyOwned(t) -} diff --git a/pkg/servregistry/service.go b/pkg/servregistry/service.go deleted file mode 100644 index 68b8b55..0000000 --- a/pkg/servregistry/service.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servregistry - -// This file contains functions that perform operations on services, -// such as create/update/delete. -// These functions belong to a ServiceRegistryBroker, defined in -// broker.go - -// ManageServ takes data from a service and peforms all necessary -// operations to reflect that data to the service registry -// -// For example: create a service in service registry or update it -// properly. -func (b *Broker) ManageServ(servData *Service) (regServ *Service, err error) { - // servData: data of the service in Kubernetes (latest update) - // regServ: data of the service currently in the service registry - - // As of now, ManageServ and ProcessNsChange only differ in the type - // they work with (namespaces vs services), everything else is basically - // duplicate code. Let's adopt a pragmatic approach: we leave it like this - // since it is easier to understand and make it better later. - - if b.Reg == nil { - return nil, ErrServRegNotProvided - } - - // -- Validate - if servData == nil { - return nil, ErrServNotProvided - } - - if len(servData.Name) == 0 { - return nil, ErrServNameNotProvided - } - - if len(servData.NsName) == 0 { - return nil, ErrNsNameNotProvided - } - - // -- Init - b.lock.Lock() - defer b.lock.Unlock() - if servData.Metadata == nil { - servData.Metadata = map[string]string{} - } - servData.Metadata[b.opMetaPair.Key] = b.opMetaPair.Value - for _, metaPair := range b.persistentMeta { - servData.Metadata[metaPair.Key] = metaPair.Value - } - - l := b.log.WithName("ManageServ").WithValues("serv-name", servData.Name) - - // -- Do stuff - l.V(1).Info("going to load service from service registry") - - regServ, err = b.Reg.GetServ(servData.NsName, servData.Name) - if err != nil { - if err != ErrNotFound { - l.Error(err, "error occurred while getting service from service registry") - return - } - - // If you're here, it means that the service does not exist. - // Let's create it. - l.V(1).Info("service does not exist in service registry, going to create it") - regServ, err = b.Reg.CreateServ(servData) - if err != nil { - l.Error(err, "error occurred while creating service in service registry") - return - } - - l.V(0).Info("service created correctly") - regServ = servData - } - - if by, exists := regServ.Metadata[b.opMetaPair.Key]; by != b.opMetaPair.Value || !exists { - // If the service is not owned (as in, managed by) us, then it's - // better not to touch it. - l.V(0).Info("service is not owned by the operator and thus will not be updated") - return - } - - if !b.deepEqualMetadata(servData.Metadata, regServ.Metadata) { - l.V(1).Info("service metadata need to be updated") - regServ, err = b.Reg.UpdateServ(servData) - if err != nil { - l.Error(err, "error while trying to update service in service registry") - return nil, err - } - } - - return -} - -// RemoveServ checks if a service can be safely deleted from the -// service registry before actually delete it. The second parameter forces -// the function to delete the service even if it is not empty. -// NOTE: setting forceNotEmpty to true will have no effect if the service -// contains endpoints not owned by the operator, and therefore the service -// will not be deleted. -// -// For example: it checks if the service is actually owned by us. -func (b *Broker) RemoveServ(nsName, servName string, forceNotEmpty bool) (err error) { - if b.Reg == nil { - return ErrServRegNotProvided - } - - // -- Validate - if len(nsName) == 0 { - return ErrNsNameNotProvided - } - - if len(servName) == 0 { - return ErrServNameNotProvided - } - - // -- Init - b.lock.Lock() - defer b.lock.Unlock() - l := b.log.WithName("RemoveServ").WithValues("serv-name", servName) - - // -- Do stuff - l.V(1).Info("going to remove service from service registry") - - // Load the service first - regServ, err := b.Reg.GetServ(nsName, servName) - if err != nil { - if err != ErrNotFound { - l.Error(err, "error occurred while removing service from service registry") - return - } - - // If you're here, it means that the servce does not exist. - // This doesn't change anything for us. - l.V(0).Info("servce does not exist in service registry, going to stop here") - return nil - } - - // Is it empty? - l.V(1).Info("checking if service is empty before deleting") - listEndp, err := b.Reg.ListEndp(nsName, servName) - if err != nil { - return - } - - if len(listEndp) > 0 && !forceNotEmpty { - l.V(0).Info("service is not empty and will not be deleted from service registry") - return ErrServNotEmpty - } - - l.V(0).Info("service is not empty: checking if it can be removed") - endps := []string{} - hasNotOwned := false - for _, endp := range listEndp { - if by, exists := endp.Metadata[b.opMetaPair.Key]; by != b.opMetaPair.Value || !exists { - hasNotOwned = true - continue - } - - endps = append(endps, endp.Name) - } - - if hasNotOwned { - // There are some endpoints not owned by the operator, so we must delete - // endpoints singularly - l.V(0).Info("service contains endpoints not owned by the operator and will not be removed from service registry") - for _, endpName := range endps { - if delErr := b.Reg.DeleteEndp(nsName, servName, endpName); delErr != nil { - l.WithValues("endp-name", endpName).Error(delErr, "error while deleting endpoint from service registry") - } - } - - return ErrServNotOwnedEndps - } - - if by, exists := regServ.Metadata[b.opMetaPair.Key]; by != b.opMetaPair.Value || !exists { - // If the service is not owned (as in, managed by) us, then it's - // better not to touch it. - l.V(0).Info("WARNING: service is not owned by the operator and will not be removed from service registry") - return ErrServNotOwnedByOp - } - - err = b.Reg.DeleteServ(nsName, servName) - if err != nil { - l.Error(err, "error while deleting service from service registry") - } - - l.V(0).Info("service deleted from service registry successfully") - return -} diff --git a/pkg/servregistry/service_registry.go b/pkg/servregistry/service_registry.go deleted file mode 100644 index 3c0dadd..0000000 --- a/pkg/servregistry/service_registry.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servregistry - -import ( - corev1 "k8s.io/api/core/v1" -) - -// ServiceRegistry is an interface containing functions that are implemented -// by a service registry. -type ServiceRegistry interface { - // GetNs returns the namespace if exists. - GetNs(name string) (*Namespace, error) - // ListNs returns a list of all namespaces. - ListNs() ([]*Namespace, error) - // CreateNs creates the namespace. - CreateNs(ns *Namespace) (*Namespace, error) - // UpdateNs updates the namespace. - UpdateNs(ns *Namespace) (*Namespace, error) - // DeleteNs deletes the namespace. - DeleteNs(name string) error - // GetServ returns the service if exists. - GetServ(nsName, servName string) (*Service, error) - // ListServ returns a list of services inside the provided namespace. - ListServ(nsName string) ([]*Service, error) - // CreateServ creates the service. - CreateServ(serv *Service) (*Service, error) - // UpdateServ updates the service. - UpdateServ(serv *Service) (*Service, error) - // DeleteServ deletes the service. - DeleteServ(nsName, servName string) error - // GetEndp returns the endpoint if exists. - GetEndp(nsName, servName, endpName string) (*Endpoint, error) - // ListEndp returns a list of endpoints belonging to the provided namespace and service. - ListEndp(nsName, servName string) ([]*Endpoint, error) - // CreateEndp creates the endpoint. - CreateEndp(endp *Endpoint) (*Endpoint, error) - // UpdateEndp updates the endpoint. - UpdateEndp(endp *Endpoint) (*Endpoint, error) - // DeleteEndp deletes the endpoint. - DeleteEndp(nsName, servName, endpName string) error - // ExtractData extracts relevant data from the provided Kubernetes namespace and service - // and returns a namespace, service and an array of endpoints with data relevant to this - // specific service registry. - ExtractData(ns *corev1.Namespace, serv *corev1.Service) (*Namespace, *Service, []*Endpoint, error) -} diff --git a/pkg/servregistry/service_test.go b/pkg/servregistry/service_test.go deleted file mode 100644 index b6271c2..0000000 --- a/pkg/servregistry/service_test.go +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servregistry - -import ( - "testing" - - a "github.com/stretchr/testify/assert" -) - -func TestManageServ(t *testing.T) { - // prepare - nsName, servName := "ns", "serv" - var f *fakeServReg - b, _ := NewBroker(f, MetadataPair{}) - - resetFake := func() { - f = newFakeStruct() - b.Reg = f - } - - resetFake() - - // Test validation - testValidation := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - invalidServData := &Service{} - regServ := &Service{} - var err error - - // no service registry provided - b.Reg = nil - regServ, err = b.ManageServ(nil) - assert.Nil(regServ) - assert.Equal(ErrServRegNotProvided, err) - - // service is nil - b.Reg = f - regServ, err = b.ManageServ(nil) - assert.Nil(regServ) - assert.Equal(ErrServNotProvided, err) - - // service has no name - regServ, err = b.ManageServ(invalidServData) - assert.Nil(regServ) - assert.Equal(ErrServNameNotProvided, err) - - // service has no namespace name - invalidServData.Name = servName - regServ, err = b.ManageServ(invalidServData) - assert.Nil(regServ) - assert.Equal(ErrNsNameNotProvided, err) - - assert.Empty(f.createdServ) - assert.Empty(f.updatedServ) - } - - // Test returns nil when an unknown error is thrown by the service registry - testUnErr := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - regServ, err := b.ManageServ(&Service{Name: "get-error", NsName: "ns"}) - assert.Nil(regServ) - assert.Error(err) - assert.NotEqual(ErrServRegNotProvided, err) - assert.NotEqual(ErrServNotProvided, err) - assert.NotEqual(ErrServNameNotProvided, err) - assert.NotEqual(ErrNsNameNotProvided, err) - - assert.Empty(f.createdServ) - assert.Empty(f.updatedServ) - } - - // Test service not owned by the operator are not modified - testNotOwned := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - one := &Service{Name: "one", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}} - two := &Service{Name: "two", NsName: nsName, Metadata: map[string]string{"key": "val"}} - f.servList = map[string]*Service{one.Name: one, two.Name: two} - - oneChange := &Service{Name: "one", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} - twoChange := &Service{Name: "two", NsName: nsName, Metadata: map[string]string{"key": "val-1"}} - - regServ, err := b.ManageServ(oneChange) - assert.Equal(one, regServ) - assert.NoError(err) - - regServ, err = b.ManageServ(twoChange) - assert.Equal(two, regServ) - assert.NoError(err) - - assert.Empty(f.createdServ) - assert.Empty(f.updatedServ) - } - - // Test services owned by the operator are modified - testOwned := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - // should return nil because an error in updating - shouldErr := &Service{Name: "update-error", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - changeErr := &Service{Name: "update-error", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} - f.servList[shouldErr.Name] = shouldErr - - regServ, err := b.ManageServ(changeErr) - assert.Nil(regServ) - assert.Error(err) - assert.Empty(f.updatedServ) - - // no error so it should return the new value - shouldOk := &Service{Name: "update", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - okChange := &Service{Name: "update", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val-1"}} - f.servList[shouldOk.Name] = shouldOk - - regServ, err = b.ManageServ(okChange) - assert.Equal(okChange, regServ) - assert.NoError(err) - - assert.Empty(f.createdServ) - assert.Len(f.updatedServ, 1) - } - - // Test services are created if they do not exist - testCreate := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - // should return nil because an error in creating - // (this also happens if someone else creates this) - shouldErr := &Service{Name: "create-error", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - regServ, err := b.ManageServ(shouldErr) - assert.Nil(regServ) - assert.Error(err) - assert.Empty(f.createdServ) - - // no error so it should return the created - shouldOk := &Service{Name: "create", NsName: nsName, Metadata: map[string]string{"key": "val"}} - regServ, err = b.ManageServ(shouldOk) - assert.Equal(shouldOk.Name, regServ.Name) - assert.Equal(shouldOk.NsName, regServ.NsName) - assert.Equal(map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, regServ.Metadata) - assert.NoError(err) - - assert.Empty(f.updatedServ) - assert.Len(f.createdServ, 1) - } - - testValidation(t) - testUnErr(t) - testNotOwned(t) - testOwned(t) - testCreate(t) -} - -func TestRemoveServ(t *testing.T) { - // prepare - nsName, servName := "ns", "serv" - var f *fakeServReg - b, _ := NewBroker(f, MetadataPair{}) - - resetFake := func() { - f = newFakeStruct() - b.Reg = f - } - - resetFake() - - // Test validation - testValidation := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - // no service registry provided - b.Reg = nil - err := b.RemoveServ(nsName, servName, false) - assert.Equal(ErrServRegNotProvided, err) - - // service name not provided - b.Reg = f - err = b.RemoveServ(nsName, "", false) - assert.Equal(ErrServNameNotProvided, err) - - // namespace name not provided - err = b.RemoveServ("", servName, false) - assert.Equal(ErrNsNameNotProvided, err) - assert.Empty(f.deletedServ) - } - - // Test returns nil when an unknown error is thrown by the service registry - testUnErr := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - err := b.RemoveServ(nsName, "get-error", false) - assert.Error(err) - assert.NotEqual(ErrServRegNotProvided, err) - assert.NotEqual(ErrServNameNotProvided, err) - assert.NotEqual(ErrNsNameNotProvided, err) - - assert.Empty(f.deletedServ) - } - - // Test services not owned by the operator are not deleted - testNotOwned := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - one := &Service{Name: "one", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}} - two := &Service{Name: "two", NsName: nsName, Metadata: map[string]string{"key": "val"}} - f.servList[one.Name] = one - f.servList[two.Name] = two - - err := b.RemoveServ(one.NsName, one.Name, false) - assert.Equal(ErrServNotOwnedByOp, err) - err = b.RemoveServ(two.NsName, two.Name, false) - assert.Equal(ErrServNotOwnedByOp, err) - assert.Empty(f.deletedServ) - } - - // Test empty owned services are deleted - testEmptyOwned := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - // unknown error - err := b.RemoveServ(nsName, "delete-error", false) - assert.NotEqual(ErrServRegNotProvided, err) - assert.NotEqual(ErrNsNameNotProvided, err) - - // when it doesn't exist, we just log but return no error - // because it doesn't change anything for us - err = b.RemoveServ(nsName, "doesnt-exist", false) - assert.NoError(err) - - // successful - toDel := &Service{Name: "to-del", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - f.servList[toDel.Name] = toDel - err = b.RemoveServ(nsName, "to-del", false) - assert.NoError(err) - assert.Len(f.deletedServ, 1) - } - - // Test not empty owned namespaces are deleted/not deleted - testNotEmptyOwned := func(tt *testing.T) { - defer resetFake() - assert := a.New(tt) - - oneOwned := &Endpoint{ - Name: "one", - ServName: servName, - NsName: nsName, - Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, - } - twoOwned := &Endpoint{ - Name: "two", - ServName: servName, - NsName: nsName, - Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}, - } - threeNotOwned := &Endpoint{ - Name: "three", - ServName: servName, - NsName: nsName, - Metadata: map[string]string{b.opMetaPair.Key: "someone-else", "key": "val"}, - } - servDel := &Service{Name: servName, NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - f.servList[servDel.Name] = servDel - - // error in listing - f.endpList["list-error"] = &Endpoint{} - err := b.RemoveServ(servDel.NsName, servDel.Name, false) - assert.Error(err) - assert.Empty(f.deletedServ) - delete(f.endpList, "list-error") - - // there is an endpoint not owned by us - f.endpList["one"] = oneOwned - f.endpList["two"] = twoOwned - f.endpList["three"] = threeNotOwned - - err = b.RemoveServ(servDel.NsName, servDel.Name, false) - assert.Empty(f.deletedEndp) - assert.Empty(f.deletedServ) - assert.Equal(ErrServNotEmpty, err) - - err = b.RemoveServ(servDel.NsName, servDel.Name, true) - assert.Len(f.deletedEndp, 2) - assert.Empty(f.deletedServ) - assert.Equal(ErrServNotOwnedEndps, err) - assert.Contains(f.deletedEndp, oneOwned.Name) - assert.Contains(f.deletedEndp, twoOwned.Name) - - // all endpoints owned by the operator, so should be successful - delete(f.endpList, threeNotOwned.Name) - f.endpList["one"] = oneOwned - f.endpList["two"] = twoOwned - f.deletedEndp = []string{} - f.deletedServ = []string{} - err = b.RemoveServ(servDel.NsName, servDel.Name, true) - assert.NoError(err) - - // error occurs in deleting service - shouldErr := &Service{Name: "delete-error", NsName: nsName, Metadata: map[string]string{b.opMetaPair.Key: b.opMetaPair.Value, "key": "val"}} - f.servList[shouldErr.Name] = shouldErr - f.deletedEndp = []string{} - f.deletedServ = []string{} - err = b.RemoveServ(shouldErr.NsName, shouldErr.Name, true) - assert.Error(err) - } - - testValidation(t) - testUnErr(t) - testNotOwned(t) - testEmptyOwned(t) - testNotEmptyOwned(t) -} diff --git a/pkg/servregistry/utils.go b/pkg/servregistry/utils.go deleted file mode 100644 index 2bbfedf..0000000 --- a/pkg/servregistry/utils.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright © 2020 Cisco -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All rights reserved. - -package servregistry - -import ( - "reflect" -) - -// deepEqualMetadata compares two metadata maps, ignoring reserved metadata -// without removing it from the maps -func (b *Broker) deepEqualMetadata(src, dst map[string]string) bool { - // Copy the two - sr := map[string]string{} - de := map[string]string{} - - for key, val := range src { - if key == b.opMetaPair.Key && val == b.opMetaPair.Value { - // Don't copy this one - continue - } - sr[key] = val - } - - for key, val := range dst { - if key == b.opMetaPair.Key && val == b.opMetaPair.Value { - // Don't copy this one - continue - } - de[key] = val - } - - return reflect.DeepEqual(sr, de) -} From 6951141fd87ee6172d50c74c0d60aee0e291e233 Mon Sep 17 00:00:00 2001 From: Elis Lulja Date: Mon, 27 Mar 2023 09:32:10 +0200 Subject: [PATCH 21/21] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20update=20dependencie?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Elis Lulja --- go.mod | 20 ++++++++++---------- go.sum | 27 +++++++++++++-------------- main.go | 2 +- utils.go | 5 ++--- 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 40b77f8..79270a9 100644 --- a/go.mod +++ b/go.mod @@ -7,19 +7,13 @@ require ( cloud.google.com/go/servicedirectory v1.9.0 github.com/CloudNativeSDWAN/serego/api v0.1.0 github.com/aws/aws-sdk-go v1.44.229 - github.com/aws/aws-sdk-go-v2 v1.17.7 github.com/aws/aws-sdk-go-v2/config v1.18.19 github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.21.0 - github.com/go-logr/logr v1.2.3 - github.com/googleapis/gax-go/v2 v2.8.0 github.com/rs/zerolog v1.29.0 github.com/stretchr/testify v1.8.2 - go.etcd.io/etcd/api/v3 v3.5.7 go.etcd.io/etcd/client/v3 v3.5.7 go.uber.org/zap v1.24.0 google.golang.org/api v0.114.0 - google.golang.org/genproto v0.0.0-20230323212658-478b75c54725 - google.golang.org/grpc v1.54.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.26.3 k8s.io/apimachinery v0.26.3 @@ -28,9 +22,10 @@ require ( ) require ( - cloud.google.com/go/compute v1.19.0 // indirect - cloud.google.com/go/iam v0.13.0 // indirect + cloud.google.com/go/compute v1.18.0 // indirect + cloud.google.com/go/iam v0.12.0 // indirect github.com/BurntSushi/toml v0.3.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.17.7 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.13.18 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 // indirect @@ -50,19 +45,21 @@ require ( github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/zapr v1.2.3 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/swag v0.19.14 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect github.com/googleapis/gax-go v1.0.3 // indirect + github.com/googleapis/gax-go/v2 v2.7.1 // indirect github.com/imdario/mergo v0.3.6 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -82,6 +79,7 @@ require ( github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + go.etcd.io/etcd/api/v3 v3.5.7 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect go.opencensus.io v0.24.0 // indirect go.uber.org/atomic v1.7.0 // indirect @@ -98,7 +96,9 @@ require ( golang.org/x/tools v0.6.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.29.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect honnef.co/go/tools v0.0.1-2020.1.4 // indirect diff --git a/go.sum b/go.sum index 610b258..c748ac6 100644 --- a/go.sum +++ b/go.sum @@ -20,14 +20,14 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iam v0.12.0 h1:DRtTY29b75ciH6Ov1PHb4/iat2CLCvrOm40Q0a6DFpE= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= @@ -176,9 +176,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= @@ -219,8 +218,8 @@ github.com/googleapis/gax-go v1.0.3/go.mod h1:QyXYajJFdARxGzjwUfbDFIse7Spkw81SJ4 github.com/googleapis/gax-go/v2 v2.0.2/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= 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/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= -github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= 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/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -646,8 +645,8 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230323212658-478b75c54725 h1:VmCWItVXcKboEMCwZaWge+1JLiTCQSngZeINF+wzO+g= -google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -662,8 +661,8 @@ 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.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= -google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -676,8 +675,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/main.go b/main.go index 34c206d..5a8b36b 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,4 @@ -// Copyright © 2020, 2021, 2022 Cisco +// Copyright © 2020 - 2023 Cisco // // SPDX-License-Identifier: Apache-2.0 // diff --git a/utils.go b/utils.go index 3757534..1c2b736 100644 --- a/utils.go +++ b/utils.go @@ -1,4 +1,4 @@ -// Copyright © 2021 Cisco +// Copyright © 2021, 2023 Cisco // // SPDX-License-Identifier: Apache-2.0 // @@ -21,7 +21,6 @@ package main import ( "context" "fmt" - "io/ioutil" "os" "strings" "time" @@ -110,7 +109,7 @@ func getAWSClient(ctx context.Context, region *string) (*servicediscovery.Client // TODO: this needs to be re-written in case allowing loading default // credentials that do exist on file system - if err := ioutil.WriteFile(tempPath, saBytes, 0644); err != nil { + if err := os.WriteFile(tempPath, saBytes, 0644); err != nil { return nil, err } opts = append(opts, config.WithSharedCredentialsFiles([]string{tempPath}))