From 1b87bf4ffe4eead4655bd205edfcd0f3b940deba Mon Sep 17 00:00:00 2001 From: Michael Nairn Date: Tue, 27 Feb 2024 21:57:36 +0000 Subject: [PATCH] feat: Add external-dns(v0.14.0) as a dependency Adds external-dns (latest released version v0.14.0) as a go module dependency and updates the dnsrecord controller and dns provider logic to align with an external-dns approach to dns management. dnsrecord changes: * Replace v1alpha1.Endpoint with externaldns Endpoint * Add GetRootDomain to DNSRecord, returns the shortest domain that is shared across all spec.Endpoints dns names. provider changes: * Remove Ensure and Delete and instead include externaldnsprovider.Provider in provider.Provider interface. * Add provider.Config struct to hold common provider configuration, currently it only handles filters. Update provider Factory constructors accept the config as input. * Set DomainFilter, ZoneTypeFilter and ZoneIDFilter in provider implementations from provider.Config. provider aws changes: * Implement AdjustEndpoints to change our generic provider specific fields for weight and geo into aws ones understood by external-dns. provider google changes: * Copy external-dns google provider * Adds implementations of funtions required to translate endpoints and resourceRecordSets into the different states. - endpointsToProviderFormat - converts a list of endpoints into a google specific format. - endpointsFromResourceRecordSets - converts a list of `ResourceRecordSet` into endpoints (google format). - resourceRecordSetFromEndpoint - converts an endpoint(google format) into a `ResourceRecordSet`. controller changes: * Update DNSRecord controller to use applyChanges which follows an external-dns process to determine a set of changes(Create/Update/Delete) that are required to be made against the provider. * Use noop registry, no owner is currently set or checked for any records. * Setup provider filters: - DomainFilter = root domain for endpoints determined by calling dnsRecord.GetRootDomain() - ZoneTypeFilter = "", public or private zones considered. - ZoneIDFilter = set to single hosted zone id (managedZone.Status.ID) * Use sync policy, all changes will be applied (Create, Update and Deletes) * Use plan with above and using the current zone(plan.Current) and spec endpoints(plan.Desired) as input. additional changes: downgrade gatewayapiv1 to v0.7.1. This is required since the external dns aws provider is including the external dns source package which has a dependency on Gateway API v0.7.1. Downgrading is less than ideal, but dns-operator shouldn't have a dependency on gateway api, and the health check code that is currently causing it will likely be removed soon anyway in favour of provider health checks. There is also an opportunity to change external-dns to prevent it including the source package since it's including here for no reason other than getting a version https://github.com/kubernetes-sigs/external-dns/blob/master/provider/aws/session.go#L72 --- Makefile | 2 +- api/v1alpha1/dnsrecord_types.go | 120 +- api/v1alpha1/dnsrecord_types_test.go | 81 ++ api/v1alpha1/zz_generated.deepcopy.go | 115 +- config/crd/bases/kuadrant.io_dnsrecords.yaml | 8 +- go.mod | 32 +- go.sum | 854 +++++++++++++- .../dnshealthcheckprobe_controller.go | 8 +- internal/controller/dnsrecord_controller.go | 135 ++- internal/controller/managedzone_controller.go | 7 +- internal/controller/suite_test.go | 16 +- internal/provider/aws/aws.go | 252 ++--- internal/provider/factory.go | 8 +- internal/provider/fake/factory.go | 6 +- internal/provider/fake/provider.go | 31 +- internal/provider/google/google.go | 585 +++++++--- internal/provider/google/google_test.go | 1005 ++++++++++++----- internal/provider/provider.go | 19 +- 18 files changed, 2372 insertions(+), 912 deletions(-) create mode 100644 api/v1alpha1/dnsrecord_types_test.go diff --git a/Makefile b/Makefile index 27de9413..27706636 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ build: manifests generate fmt vet ## Build manager binary. .PHONY: run run: manifests generate fmt vet ## Run a controller from your host. - go run ./cmd/main.go + go run ./cmd/main.go --zap-log-level=3 # If you wish built the manager image targeting other platforms you can use the --platform flag. # (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. diff --git a/api/v1alpha1/dnsrecord_types.go b/api/v1alpha1/dnsrecord_types.go index 0164e41f..89e20f2b 100644 --- a/api/v1alpha1/dnsrecord_types.go +++ b/api/v1alpha1/dnsrecord_types.go @@ -18,93 +18,12 @@ package v1alpha1 import ( "fmt" + "strings" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + externaldns "sigs.k8s.io/external-dns/endpoint" ) -// ProviderSpecificProperty holds the name and value of a configuration which is specific to individual DNS providers -type ProviderSpecificProperty struct { - Name string `json:"name,omitempty"` - Value string `json:"value,omitempty"` -} - -// Targets is a representation of a list of targets for an endpoint. -type Targets []string - -// TTL is a structure defining the TTL of a DNS record -type TTL int64 - -// Labels store metadata related to the endpoint -// it is then stored in a persistent storage via serialization -type Labels map[string]string - -// ProviderSpecific holds configuration which is specific to individual DNS providers -type ProviderSpecific []ProviderSpecificProperty - -// Endpoint is a high-level way of a connection between a service and an IP -type Endpoint struct { - // The hostname of the DNS record - DNSName string `json:"dnsName,omitempty"` - // The targets the DNS record points to - Targets Targets `json:"targets,omitempty"` - // RecordType type of record, e.g. CNAME, A, SRV, TXT etc - RecordType string `json:"recordType,omitempty"` - // Identifier to distinguish multiple records with the same name and type (e.g. Route53 records with routing policies other than 'simple') - SetIdentifier string `json:"setIdentifier,omitempty"` - // TTL for the record - RecordTTL TTL `json:"recordTTL,omitempty"` - // Labels stores labels defined for the Endpoint - // +optional - Labels Labels `json:"labels,omitempty"` - // ProviderSpecific stores provider specific config - // +optional - ProviderSpecific ProviderSpecific `json:"providerSpecific,omitempty"` -} - -// SetID returns an id that should be unique across a set of endpoints -func (e *Endpoint) SetID() string { - return e.DNSName + e.SetIdentifier -} - -// WithSetIdentifier applies the given set identifier to the endpoint. -func (e *Endpoint) WithSetIdentifier(setIdentifier string) *Endpoint { - e.SetIdentifier = setIdentifier - return e -} - -// GetProviderSpecificProperty returns a ProviderSpecificProperty if the property exists. -func (e *Endpoint) GetProviderSpecificProperty(key string) (ProviderSpecificProperty, bool) { - for _, providerSpecific := range e.ProviderSpecific { - if providerSpecific.Name == key { - return providerSpecific, true - } - } - return ProviderSpecificProperty{}, false -} - -// SetProviderSpecific sets a provider specific key/value pair. -func (e *Endpoint) SetProviderSpecific(name, value string) { - if e.ProviderSpecific == nil { - e.ProviderSpecific = ProviderSpecific{} - } - - for i, pair := range e.ProviderSpecific { - if pair.Name == name { - e.ProviderSpecific[i].Value = value - return - } - } - - e.ProviderSpecific = append(e.ProviderSpecific, ProviderSpecificProperty{ - Name: name, - Value: value, - }) -} - -func (e *Endpoint) String() string { - return fmt.Sprintf("%s %d IN %s %s %s %s", e.DNSName, e.RecordTTL, e.RecordType, e.SetIdentifier, e.Targets, e.ProviderSpecific) -} - // DNSRecordSpec defines the desired state of DNSRecord type DNSRecordSpec struct { // +kubebuilder:validation:Required @@ -112,7 +31,7 @@ type DNSRecordSpec struct { ManagedZoneRef *ManagedZoneReference `json:"managedZone,omitempty"` // +kubebuilder:validation:MinItems=1 // +optional - Endpoints []*Endpoint `json:"endpoints,omitempty"` + Endpoints []*externaldns.Endpoint `json:"endpoints,omitempty"` } // DNSRecordStatus defines the observed state of DNSRecord @@ -140,7 +59,7 @@ type DNSRecordStatus struct { // // Note: This will not be required if/when we switch to using external-dns since when // running with a "sync" policy it will clean up unused records automatically. - Endpoints []*Endpoint `json:"endpoints,omitempty"` + Endpoints []*externaldns.Endpoint `json:"endpoints,omitempty"` } //+kubebuilder:object:root=true @@ -182,6 +101,37 @@ const ( DefaultGeo string = "default" ) +// GetRootDomain returns the shortest domain that is shared across all spec.Endpoints dns names. +// Validates that all endpoints share an equal root domain and returns an error if they don't. +func (s *DNSRecord) GetRootDomain() (string, error) { + domain := "" + dnsNames := []string{} + for idx := range s.Spec.Endpoints { + dnsNames = append(dnsNames, s.Spec.Endpoints[idx].DNSName) + } + for idx := range dnsNames { + if domain == "" { + domain = dnsNames[0] + continue + } + if len(domain) > len(dnsNames[idx]) { + domain = dnsNames[idx] + } + } + + if domain == "" { + return "", fmt.Errorf("unable to determine root domain from %v", dnsNames) + } + + for idx := range dnsNames { + if !strings.HasSuffix(dnsNames[idx], domain) { + return "", fmt.Errorf("inconsitent domains, got %s, expected suffix %s", dnsNames[idx], domain) + } + } + + return domain, nil +} + func init() { SchemeBuilder.Register(&DNSRecord{}, &DNSRecordList{}) } diff --git a/api/v1alpha1/dnsrecord_types_test.go b/api/v1alpha1/dnsrecord_types_test.go new file mode 100644 index 00000000..4d0cacd1 --- /dev/null +++ b/api/v1alpha1/dnsrecord_types_test.go @@ -0,0 +1,81 @@ +package v1alpha1 + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/external-dns/endpoint" +) + +func TestDNSRecord_GetRootDomain(t *testing.T) { + tests := []struct { + name string + dnsNames []string + want string + wantErr bool + }{ + { + name: "single endpoint", + dnsNames: []string{ + "test.example.com", + }, + want: "test.example.com", + wantErr: false, + }, + { + name: "multiple endpoints matching", + dnsNames: []string{ + "bar.baz.test.example.com", + "bar.test.example.com", + "test.example.com", + "foo.bar.baz.test.example.com", + }, + want: "test.example.com", + wantErr: false, + }, + { + name: "no endpoints", + dnsNames: []string{}, + want: "", + wantErr: true, + }, + { + name: "multiple endpoints mismatching", + dnsNames: []string{ + "foo.bar.test.example.com", + "bar.test.example.com", + "baz.example.com", + }, + want: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &DNSRecord{ + TypeMeta: metav1.TypeMeta{ + Kind: "DNSRecord", + APIVersion: GroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "testRecord", + Namespace: "testNS", + }, + Spec: DNSRecordSpec{ + Endpoints: []*endpoint.Endpoint{}, + }, + } + for idx := range tt.dnsNames { + s.Spec.Endpoints = append(s.Spec.Endpoints, &endpoint.Endpoint{DNSName: tt.dnsNames[idx]}) + } + got, err := s.GetRootDomain() + if (err != nil) != tt.wantErr { + t.Errorf("GetRootDomain() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("GetRootDomain() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index bb4e529b..9b68c431 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -24,6 +24,7 @@ package v1alpha1 import ( "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/external-dns/endpoint" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -255,11 +256,11 @@ func (in *DNSRecordSpec) DeepCopyInto(out *DNSRecordSpec) { } if in.Endpoints != nil { in, out := &in.Endpoints, &out.Endpoints - *out = make([]*Endpoint, len(*in)) + *out = make([]*endpoint.Endpoint, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(Endpoint) + *out = new(endpoint.Endpoint) (*in).DeepCopyInto(*out) } } @@ -288,11 +289,11 @@ func (in *DNSRecordStatus) DeepCopyInto(out *DNSRecordStatus) { } if in.Endpoints != nil { in, out := &in.Endpoints, &out.Endpoints - *out = make([]*Endpoint, len(*in)) + *out = make([]*endpoint.Endpoint, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(Endpoint) + *out = new(endpoint.Endpoint) (*in).DeepCopyInto(*out) } } @@ -309,59 +310,6 @@ func (in *DNSRecordStatus) DeepCopy() *DNSRecordStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Endpoint) DeepCopyInto(out *Endpoint) { - *out = *in - if in.Targets != nil { - in, out := &in.Targets, &out.Targets - *out = make(Targets, len(*in)) - copy(*out, *in) - } - if in.Labels != nil { - in, out := &in.Labels, &out.Labels - *out = make(Labels, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.ProviderSpecific != nil { - in, out := &in.ProviderSpecific, &out.ProviderSpecific - *out = make(ProviderSpecific, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Endpoint. -func (in *Endpoint) DeepCopy() *Endpoint { - if in == nil { - return nil - } - out := new(Endpoint) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in Labels) DeepCopyInto(out *Labels) { - { - in := &in - *out = make(Labels, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Labels. -func (in Labels) DeepCopy() Labels { - if in == nil { - return nil - } - out := new(Labels) - in.DeepCopyInto(out) - return *out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ManagedHost) DeepCopyInto(out *ManagedHost) { *out = *in @@ -529,56 +477,3 @@ func (in *ProviderRef) DeepCopy() *ProviderRef { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in ProviderSpecific) DeepCopyInto(out *ProviderSpecific) { - { - in := &in - *out = make(ProviderSpecific, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderSpecific. -func (in ProviderSpecific) DeepCopy() ProviderSpecific { - if in == nil { - return nil - } - out := new(ProviderSpecific) - in.DeepCopyInto(out) - return *out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProviderSpecificProperty) DeepCopyInto(out *ProviderSpecificProperty) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderSpecificProperty. -func (in *ProviderSpecificProperty) DeepCopy() *ProviderSpecificProperty { - if in == nil { - return nil - } - out := new(ProviderSpecificProperty) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in Targets) DeepCopyInto(out *Targets) { - { - in := &in - *out = make(Targets, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Targets. -func (in Targets) DeepCopy() Targets { - if in == nil { - return nil - } - out := new(Targets) - in.DeepCopyInto(out) - return *out -} diff --git a/config/crd/bases/kuadrant.io_dnsrecords.yaml b/config/crd/bases/kuadrant.io_dnsrecords.yaml index ef73c0d3..ac503169 100644 --- a/config/crd/bases/kuadrant.io_dnsrecords.yaml +++ b/config/crd/bases/kuadrant.io_dnsrecords.yaml @@ -69,8 +69,8 @@ spec: format: int64 type: integer recordType: - description: RecordType type of record, e.g. CNAME, A, SRV, - TXT etc + description: RecordType type of record, e.g. CNAME, A, AAAA, + SRV, TXT etc type: string setIdentifier: description: Identifier to distinguish multiple records with @@ -206,8 +206,8 @@ spec: format: int64 type: integer recordType: - description: RecordType type of record, e.g. CNAME, A, SRV, - TXT etc + description: RecordType type of record, e.g. CNAME, A, AAAA, + SRV, TXT etc type: string setIdentifier: description: Identifier to distinguish multiple records with diff --git a/go.mod b/go.mod index 0f35086a..49124e48 100644 --- a/go.mod +++ b/go.mod @@ -3,25 +3,35 @@ module github.com/kuadrant/dns-operator go 1.21 require ( - github.com/aws/aws-sdk-go v1.44.175 + github.com/aws/aws-sdk-go v1.44.311 github.com/go-logr/logr v1.2.4 github.com/onsi/ginkgo/v2 v2.11.0 github.com/onsi/gomega v1.27.10 github.com/prometheus/client_golang v1.17.0 - google.golang.org/api v0.126.0 + github.com/sirupsen/logrus v1.9.3 + google.golang.org/api v0.134.0 k8s.io/api v0.28.3 k8s.io/apimachinery v0.28.3 k8s.io/client-go v0.28.3 k8s.io/utils v0.0.0-20230726121419-3b25d923346b sigs.k8s.io/controller-runtime v0.16.3 - sigs.k8s.io/gateway-api v1.0.0 + sigs.k8s.io/external-dns v0.14.0 + sigs.k8s.io/gateway-api v0.7.1 ) require ( cloud.google.com/go/compute v1.20.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect + code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f // indirect + github.com/F5Networks/k8s-bigip-ctlr/v2 v2.13.1 // indirect + github.com/Masterminds/semver v1.4.2 // indirect + github.com/alecthomas/kingpin v2.2.6+incompatible // indirect + github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect + github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 // indirect + github.com/datawire/ambassador v1.12.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch/v5 v5.7.0 // indirect @@ -40,18 +50,22 @@ require ( github.com/google/pprof v0.0.0-20221212185716-aee1124e3a93 // indirect github.com/google/s2a-go v0.1.4 // indirect github.com/google/uuid v1.3.1 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.11.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/linki/instrumented_http v0.3.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect 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/openshift/api v0.0.0-20230607130528-611114dca681 // indirect + github.com/openshift/client-go v0.0.0-20230607134213-3cd0021bbee3 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/projectcontour/contour v1.25.2 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect @@ -70,12 +84,16 @@ require ( golang.org/x/tools v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect - google.golang.org/grpc v1.55.0 // indirect + google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230720185612-659f7aaaa771 // indirect + google.golang.org/grpc v1.56.3 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + istio.io/api v1.19.0-alpha.1 // indirect + istio.io/client-go v1.18.1 // indirect k8s.io/apiextensions-apiserver v0.28.3 // indirect k8s.io/component-base v0.28.3 // indirect k8s.io/klog/v2 v2.100.1 // indirect diff --git a/go.sum b/go.sum index aabe1a2a..7dfc0dde 100644 --- a/go.sum +++ b/go.sum @@ -1,69 +1,323 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f h1:UrKzEwTgeiff9vxdrfdqxibzpWjxLnuXDI5m6z3GJAk= +code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI= +git.lukeshu.com/go/libsystemd v0.5.3/go.mod h1:FfDoP0i92r4p5Vn4NCLxvjkd7rCOe6otPa4L6hZg9WM= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +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/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/F5Networks/k8s-bigip-ctlr/v2 v2.13.1 h1:GgMdpvQjm7WBuO2xRwMuaEPwc3fdUbAljf+3uxwk8MA= +github.com/F5Networks/k8s-bigip-ctlr/v2 v2.13.1/go.mod h1:GJ5fTJ9GuGe2CzEYd8hk/KinNXDNJ0QYqWluiPdLn/s= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig v2.17.1+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA= +github.com/Masterminds/squirrel v1.2.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= +github.com/Masterminds/squirrel v1.4.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= +github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +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/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI= +github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +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-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/brotli v0.0.0-20190621154722-5f990b63d2d6/go.mod h1:+lx6/Aqd1kLJ1GQfkvOnaZ1WGmLpMpbprPuIOOZX30U= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/aws/aws-sdk-go v1.44.175 h1:c0NzHHnPXV5kJoTUFQxFN5cUPpX1SxO635XnwL5/oIY= -github.com/aws/aws-sdk-go v1.44.175/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aokoli/goutils v1.1.0/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +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/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.44.311 h1:60i8hyVMOXqabKJQPCq4qKRBQ6hRafI/WOcDxGM+J7Q= +github.com/aws/aws-sdk-go v1.44.311/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +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/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +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.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 h1:rdRS5BT13Iae9ssvcslol66gfOOXjaLYwqerEn/cl9s= +github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381/go.mod h1:e5+USP2j8Le2M0Jo3qKPFnNhuo1wueU4nWHCXBOfQ14= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +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/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/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +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/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +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/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/datawire/ambassador v1.12.4 h1:g+agFHayLqETkCgFgEQi9qk4zakE0UAhgK8xVUEcDDI= +github.com/datawire/ambassador v1.12.4/go.mod h1:2grBLdYgILzrgTpenDMB5OeyhObIUaT+KwkLkZI1KDE= +github.com/datawire/dlib v1.2.0/go.mod h1:t0upKFHApJskdVFH/gyksG5+vMCl0GCKeEZIEJBBv4g= +github.com/datawire/pf v0.0.0-20180510150411-31a823f9495a/go.mod h1:H8uUmE8qqo7z9u30MYB9riLyRckPHOPBk9ZdCuH+dQQ= 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/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= +github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As= +github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +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/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +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/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +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/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/ecodia/golang-awaitility v0.0.0-20180710094957-fb55e59708c7/go.mod h1:etn7NbLy5UviLk20XMZbSn/0AigF3Zfx7wwaEZ3fyIk= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +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.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= 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.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= -github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/envoyproxy/protoc-gen-validate v0.3.0-java.0.20200609174644-bd816e4522c1/go.mod h1:bjmEhrMDubXDd0uKxnWwRmgSsiEv2CkJliIHnj6ETm8= +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 v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc= github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +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/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +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/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +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/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= +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-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= +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/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +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/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +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-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= +github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= +github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godror/godror v0.13.3/go.mod h1:2ouUT4kdhUBk7TAkHWD4SN0CdI0pgEQbo8FVHhbSKWg= +github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/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-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +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-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +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= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -78,6 +332,13 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS 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/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= +github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= +github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= +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-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -91,78 +352,387 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/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/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20221212185716-aee1124e3a93 h1:D5iJJZKAi0rU4e/5E58BkrnN+xeCDjAIqcm1GGxAGSI= github.com/google/pprof v0.0.0-20221212185716-aee1124e3a93/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= +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.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/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/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= -github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= +github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= +github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +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/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= +github.com/gookit/color v1.2.3/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +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/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +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.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +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/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +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/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 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/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 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/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.9/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.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/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +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/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +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.2/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/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 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/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/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/linki/instrumented_http v0.3.0 h1:dsN92+mXpfZtjJraartcQ99jnuw7fqsnPDjr85ma2dA= +github.com/linki/instrumented_http v0.3.0/go.mod h1:pjYbItoegfuVi2GUOMhEqzvm/SJKuEL3H0tc8QRLRFk= +github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= +github.com/lyft/protoc-gen-star v0.4.10/go.mod h1:mE8fbna26u7aEA2QCVvvfBU/ZrPgocG1206xAFPcs94= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +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/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/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11 h1:YFh+sjyJTMQSYjKwM4dFKhJPJC/wfo98tPUc17HdoYw= +github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= +github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.6/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +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/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= +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.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/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.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +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.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/openshift/api v0.0.0-20230607130528-611114dca681 h1:kSvo4fjZyYRu7z7PVkZlqcYhoS4mZHVFYVUkG3WkvIE= +github.com/openshift/api v0.0.0-20230607130528-611114dca681/go.mod h1:4VWG+W22wrB4HfBL88P40DxLEpSOaiBVxUnfalfJo9k= +github.com/openshift/client-go v0.0.0-20230607134213-3cd0021bbee3 h1:uVCq/Sx2y4UZh+qCsCL1BBUJpc3DULHkN4j7XHHgHtw= +github.com/openshift/client-go v0.0.0-20230607134213-3cd0021bbee3/go.mod h1:M+VUIcqx5IvgzejcbgmQnxETPrXRYlcufHpw2bAgz9Y= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2 h1:CXwSGu/LYmbjEab5aMCs5usQRVBGThelUKBNnoSOuso= +github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2/go.mod h1:L3UMQOThbttwfYRNFOWLLVXMhk5Lkio4GGOtw5UrxS0= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +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/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/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/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/projectcontour/contour v1.25.2 h1:68FO5+PJ10UTF5cwj2IATTKPYSkW0jxTg3Q//8A6nCI= +github.com/projectcontour/contour v1.25.2/go.mod h1:yfnLls/nZckkbrjZpN2Y96T3iSoWL325YGEw8eueEJ0= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/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.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +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/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3/go.mod h1:rtQlpHw+eR6UrqaS3kX1VYeaCxzCVdimDS7g5Ln4pPc= +github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180725160413-e900ae048470/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +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/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +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/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +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-0.20171106142849-4c012f6dcd95/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/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= 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 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -171,25 +741,83 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +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/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +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.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +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.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.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.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-20190325154230-a5d413f7728c/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-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-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -200,25 +828,48 @@ golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= 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= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/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.2/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.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +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-20181023162649-9b4f9f5ad519/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-20181201002055-351d144fa1fc/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-20190125091013-d26f9f9a57f3/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-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 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-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -227,12 +878,16 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +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-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= 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= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -240,10 +895,39 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180425194835-bb9c189858d9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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-20181026203630-95b1ffbd15a5/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-20181122145206-62eef0e2fa9b/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/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-20190916202348-b4ddaad3f8a3/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-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -251,6 +935,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= @@ -260,7 +945,10 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -268,14 +956,35 @@ 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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +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-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-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +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-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -286,34 +995,56 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= -google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.134.0 h1:ktL4Goua+UBgoP1eL1/60LwZJqa1sIzkLmvoR3hR6Gw= +google.golang.org/api v0.134.0/go.mod h1:sjRL3UnjTx5UqNQS9EWr9N8p7xbHpy1k0XGRLCf3Spk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 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.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= 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= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= +google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 h1:XVeBY8d/FaK4848myy41HBqnDwvxeV3zMZhwN1TvAMU= +google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230720185612-659f7aaaa771 h1:Z8qdAF9GFsmcUuWQ5KVYIpP3PCKydn/YKORnghIalu4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230720185612-659f7aaaa771/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 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= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 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.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= 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= @@ -327,45 +1058,128 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +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-20141024133853-64131543e789/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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +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/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= 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/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +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-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +helm.sh/helm/v3 v3.2.4/go.mod h1:ZaXz/vzktgwjyGGFbUWtIQkscfE7WYoRGP2szqAFHR0= +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-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +istio.io/api v1.19.0-alpha.1 h1:piKxgZ1Y9abNin/zw9cp6AFKhhC3Z2UmJRTN0Tm5FEY= +istio.io/api v1.19.0-alpha.1/go.mod h1:dDMe1TsOtrRoUlBzdxqNolWXpXPQjLfbcXvqPMtQ6eo= +istio.io/client-go v1.18.1 h1:qSpKeJ0+3L9wAEfs30KaTWkifhz7YRmyXsOPnC+zMqk= +istio.io/client-go v1.18.1/go.mod h1:ha62DtaYYStYdisMZw9OG5iG92irhr2sWK7C38qCdqI= +k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= +k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= +k8s.io/api v0.18.4/go.mod h1:lOIQAKYgai1+vz9J7YcDZwC26Z0zQewYOGWdyIPUUQ4= k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM= k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc= +k8s.io/apiextensions-apiserver v0.18.0/go.mod h1:18Cwn1Xws4xnWQNC00FLq1E350b9lUF+aOdIWDOZxgo= +k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= +k8s.io/apiextensions-apiserver v0.18.4/go.mod h1:NYeyeYq4SIpFlPxSAB6jHPIdvu3hL0pc36wuRChybio= k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08= k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc= +k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= +k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= +k8s.io/apimachinery v0.18.4/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= +k8s.io/apiserver v0.18.0/go.mod h1:3S2O6FeBBd6XTo0njUrLxiqk8GNy6wWOftjhJcXYnjw= +k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= +k8s.io/apiserver v0.18.4/go.mod h1:q+zoFct5ABNnYkGIaGQ3bcbUNdmPyOCoEBcg51LChY8= +k8s.io/cli-runtime v0.18.0/go.mod h1:1eXfmBsIJosjn9LjEBUd2WVPoPAY9XGTqTFcPMIBsUQ= +k8s.io/cli-runtime v0.18.4/go.mod h1:9/hS/Cuf7NVzWR5F/5tyS6xsnclxoPLVtwhnkJG1Y4g= +k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8= +k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= +k8s.io/client-go v0.18.4/go.mod h1:f5sXwL4yAZRkAtzOxRWUhA/N8XzGCb+nPZI8PfobZ9g= k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= +k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= +k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= +k8s.io/code-generator v0.18.4/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/component-base v0.18.0/go.mod h1:u3BCg0z1uskkzrnAKFzulmYaEpZF7XC9Pf/uFyb1v2c= +k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= +k8s.io/component-base v0.18.4/go.mod h1:7jr/Ef5PGmKwQhyAz/pjByxJbC58mhKAhiaDu0vXfPk= k8s.io/component-base v0.28.3 h1:rDy68eHKxq/80RiMb2Ld/tbH8uAE75JdCqJyi6lXMzI= k8s.io/component-base v0.28.3/go.mod h1:fDJ6vpVNSk6cRo5wmDa6eKIG7UlIQkaFmZN2fYgIUD8= +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/helm v2.16.9+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI= +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/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/kubectl v0.18.0/go.mod h1:LOkWx9Z5DXMEg5KtOjHhRiC1fqJPLyCr3KtQgEolCkU= +k8s.io/kubectl v0.18.4/go.mod h1:EzB+nfeUWk6fm6giXQ8P4Fayw3dsN+M7Wjy23mTRtB0= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/metrics v0.18.0/go.mod h1:8aYTW18koXqjLVKL7Ds05RPMX9ipJZI3mywYvBOxXd4= +k8s.io/metrics v0.18.4/go.mod h1:luze4fyI9JG4eLDZy0kFdYEebqNfi0QrG4xNEbPkHOs= +k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= +sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gEORz0efEja7A= sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4= sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= -sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs= -sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c= +sigs.k8s.io/controller-tools v0.3.1-0.20200517180335-820a4a27ea84/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= +sigs.k8s.io/external-dns v0.14.0 h1:pgY3DdyoBei+ej1nyZUzRt9ECm9RRwb9s6/CPWe51tc= +sigs.k8s.io/external-dns v0.14.0/go.mod h1:d4Knr/BFz8U1Lc6yLhCzTRP6nJOz6fqR/MnqqJPcIlU= +sigs.k8s.io/gateway-api v0.7.1 h1:Tts2jeepVkPA5rVG/iO+S43s9n7Vp7jCDhZDQYtPigQ= +sigs.k8s.io/gateway-api v0.7.1/go.mod h1:Xv0+ZMxX0lu1nSSDIIPEfbVztgNZ+3cfiYrJsa2Ooso= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= +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/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/internal/controller/dnshealthcheckprobe_controller.go b/internal/controller/dnshealthcheckprobe_controller.go index 0424d53e..8fd92def 100644 --- a/internal/controller/dnshealthcheckprobe_controller.go +++ b/internal/controller/dnshealthcheckprobe_controller.go @@ -15,7 +15,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/log" - gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" + gatewayapiv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" "github.com/kuadrant/dns-operator/api/v1alpha1" "github.com/kuadrant/dns-operator/internal/common/slice" @@ -192,7 +192,7 @@ func getAdditionalHeaders(ctx context.Context, clt client.Client, probeObj *v1al return additionalHeaders, nil } -func (r *DNSHealthCheckProbeReconciler) getGatewayFor(ctx context.Context, probe *v1alpha1.DNSHealthCheckProbe) (*gatewayapiv1.Gateway, bool, error) { +func (r *DNSHealthCheckProbeReconciler) getGatewayFor(ctx context.Context, probe *v1alpha1.DNSHealthCheckProbe) (*gatewayapiv1beta1.Gateway, bool, error) { if probe.Labels == nil { return nil, false, nil } @@ -209,7 +209,7 @@ func (r *DNSHealthCheckProbeReconciler) getGatewayFor(ctx context.Context, probe Namespace: namespace, } - gw := &gatewayapiv1.Gateway{} + gw := &gatewayapiv1beta1.Gateway{} if err := r.Client.Get(ctx, objKey, gw); err != nil { return nil, false, err } @@ -244,7 +244,7 @@ func (r *DNSHealthCheckProbeReconciler) newProbeNotifierFor(ctx context.Context, } // Find the listener in the Gateway that matches the DNSRecord - listener, ok := slice.Find(gateway.Spec.Listeners, func(listener gatewayapiv1.Listener) bool { + listener, ok := slice.Find(gateway.Spec.Listeners, func(listener gatewayapiv1beta1.Listener) bool { dnsRecordName := fmt.Sprintf("%s-%s", gateway.Name, listener.Name) return dnsRecord.Name == dnsRecordName }) diff --git a/internal/controller/dnsrecord_controller.go b/internal/controller/dnsrecord_controller.go index 8aea0934..3a6fe412 100644 --- a/internal/controller/dnsrecord_controller.go +++ b/internal/controller/dnsrecord_controller.go @@ -31,6 +31,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/log" + externaldnsendpoint "sigs.k8s.io/external-dns/endpoint" + externaldnsplan "sigs.k8s.io/external-dns/plan" + externaldnsprovider "sigs.k8s.io/external-dns/provider" + externaldnsregistry "sigs.k8s.io/external-dns/registry" "github.com/kuadrant/dns-operator/api/v1alpha1" "github.com/kuadrant/dns-operator/internal/common/conditions" @@ -55,7 +59,7 @@ type DNSRecordReconciler struct { //+kubebuilder:rbac:groups=kuadrant.io,resources=dnsrecords/finalizers,verbs=update func (r *DNSRecordReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - _ = log.FromContext(ctx) + logger := log.FromContext(ctx) previous := &v1alpha1.DNSRecord{} err := r.Client.Get(ctx, client.ObjectKey{Namespace: req.Namespace, Name: req.Name}, previous) @@ -68,23 +72,21 @@ func (r *DNSRecordReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( } dnsRecord := previous.DeepCopy() - log.Log.V(3).Info("DNSRecordReconciler Reconcile", "dnsRecord", dnsRecord) - if dnsRecord.DeletionTimestamp != nil && !dnsRecord.DeletionTimestamp.IsZero() { if err := r.deleteRecord(ctx, dnsRecord); err != nil { - log.Log.Error(err, "Failed to delete DNSRecord", "record", dnsRecord) + logger.Error(err, "Failed to delete DNSRecord") return ctrl.Result{}, err } + logger.Info("Removing Finalizer", "name", DNSRecordFinalizer) controllerutil.RemoveFinalizer(dnsRecord, DNSRecordFinalizer) - - err = r.Update(ctx, dnsRecord) - if err != nil { + if err = r.Update(ctx, dnsRecord); client.IgnoreNotFound(err) != nil { return ctrl.Result{}, err } return ctrl.Result{}, nil } if !controllerutil.ContainsFinalizer(dnsRecord, DNSRecordFinalizer) { + logger.Info("Adding Finalizer", "name", DNSRecordFinalizer) controllerutil.AddFinalizer(dnsRecord, DNSRecordFinalizer) err = r.Update(ctx, dnsRecord) if err != nil { @@ -96,7 +98,7 @@ func (r *DNSRecordReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( var reason, message string status := metav1.ConditionTrue reason = "ProviderSuccess" - message = "Provider ensured the managed zone" + message = "Provider ensured the dns record" // Publish the record err = r.publishRecord(ctx, dnsRecord) @@ -134,6 +136,8 @@ func (r *DNSRecordReconciler) SetupWithManager(mgr ctrl.Manager) error { // deleteRecord deletes record(s) in the DNSPRovider(i.e. route53) configured by the ManagedZone assigned to this // DNSRecord (dnsRecord.Status.ParentManagedZone). func (r *DNSRecordReconciler) deleteRecord(ctx context.Context, dnsRecord *v1alpha1.DNSRecord) error { + logger := log.FromContext(ctx) + managedZone := &v1alpha1.ManagedZone{ ObjectMeta: metav1.ObjectMeta{ Name: dnsRecord.Spec.ManagedZoneRef.Name, @@ -151,23 +155,18 @@ func (r *DNSRecordReconciler) deleteRecord(ctx context.Context, dnsRecord *v1alp return fmt.Errorf("the managed zone is not in a ready state : %s", managedZone.Name) } - dnsProvider, err := r.ProviderFactory.ProviderFor(ctx, managedZone) - if err != nil { - return err - } - - err = dnsProvider.Delete(dnsRecord, managedZone) + err = r.applyChanges(ctx, dnsRecord, managedZone, true) if err != nil { if strings.Contains(err.Error(), "was not found") || strings.Contains(err.Error(), "notFound") { - log.Log.Info("Record not found in managed zone, continuing", "dnsRecord", dnsRecord.Name, "managedZone", managedZone.Name) + logger.Info("Record not found in managed zone, continuing", "dnsRecord", dnsRecord.Name, "managedZone", managedZone.Name) return nil } else if strings.Contains(err.Error(), "no endpoints") { - log.Log.Info("DNS record had no endpoint, continuing", "dnsRecord", dnsRecord.Name, "managedZone", managedZone.Name) + logger.Info("DNS record had no endpoint, continuing", "dnsRecord", dnsRecord.Name, "managedZone", managedZone.Name) return nil } return err } - log.Log.Info("Deleted DNSRecord in manage zone", "dnsRecord", dnsRecord.Name, "managedZone", managedZone.Name) + logger.Info("Deleted DNSRecord in manage zone", "dnsRecord", dnsRecord.Name, "managedZone", managedZone.Name) return nil } @@ -175,6 +174,7 @@ func (r *DNSRecordReconciler) deleteRecord(ctx context.Context, dnsRecord *v1alp // publishRecord publishes record(s) to the DNSPRovider(i.e. route53) configured by the ManagedZone assigned to this // DNSRecord (dnsRecord.Status.ParentManagedZone). func (r *DNSRecordReconciler) publishRecord(ctx context.Context, dnsRecord *v1alpha1.DNSRecord) error { + logger := log.FromContext(ctx) managedZone := &v1alpha1.ManagedZone{ ObjectMeta: metav1.ObjectMeta{ @@ -193,19 +193,15 @@ func (r *DNSRecordReconciler) publishRecord(ctx context.Context, dnsRecord *v1al } if dnsRecord.Generation == dnsRecord.Status.ObservedGeneration { - log.Log.V(3).Info("Skipping managed zone to which the DNS dnsRecord is already published", "dnsRecord", dnsRecord.Name, "managedZone", managedZone.Name) + logger.V(3).Info("Skipping managed zone to which the DNS dnsRecord is already published", "dnsRecord", dnsRecord.Name, "managedZone", managedZone.Name) return nil } - dnsProvider, err := r.ProviderFactory.ProviderFor(ctx, managedZone) - if err != nil { - return err - } - err = dnsProvider.Ensure(dnsRecord, managedZone) + err = r.applyChanges(ctx, dnsRecord, managedZone, false) if err != nil { return err } - log.Log.Info("Published DNSRecord to manage zone", "dnsRecord", dnsRecord.Name, "managedZone", managedZone.Name) + logger.Info("Published DNSRecord to manage zone", "dnsRecord", dnsRecord.Name, "managedZone", managedZone.Name) return nil } @@ -221,3 +217,94 @@ func setDNSRecordCondition(dnsRecord *v1alpha1.DNSRecord, conditionType string, } meta.SetStatusCondition(&dnsRecord.Status.Conditions, cond) } + +func (r *DNSRecordReconciler) applyChanges(ctx context.Context, dnsRecord *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone, isDelete bool) error { + logger := log.FromContext(ctx) + + rootDomain, err := dnsRecord.GetRootDomain() + if err != nil { + return err + } + if !strings.HasSuffix(rootDomain, managedZone.Spec.DomainName) { + return fmt.Errorf("inconsitent domains, does not match managedzone, got %s, expected suffix %s", rootDomain, managedZone.Spec.DomainName) + } + rootDomainFilter := externaldnsendpoint.NewDomainFilter([]string{rootDomain}) + + providerConfig := provider.Config{ + DomainFilter: externaldnsendpoint.NewDomainFilter([]string{managedZone.Spec.DomainName}), + ZoneTypeFilter: externaldnsprovider.NewZoneTypeFilter(""), + ZoneIDFilter: externaldnsprovider.NewZoneIDFilter([]string{managedZone.Status.ID}), + } + logger.V(3).Info("applyChanges", "rootDomain", rootDomain, "rootDomainFilter", rootDomainFilter, "providerConfig", providerConfig) + dnsProvider, err := r.ProviderFactory.ProviderFor(ctx, managedZone, providerConfig) + if err != nil { + return err + } + + registry, err := externaldnsregistry.NewNoopRegistry(dnsProvider) + if err != nil { + return err + } + + policyID := "sync" + policy, exists := externaldnsplan.Policies[policyID] + if !exists { + return fmt.Errorf("unknown policy: %s", policyID) + } + + managedDNSRecordTypes := []string{externaldnsendpoint.RecordTypeA, externaldnsendpoint.RecordTypeAAAA, externaldnsendpoint.RecordTypeCNAME} + excludeDNSRecordTypes := []string{} + + //If we are deleting set the expected endpoints to an empty array + if isDelete { + dnsRecord.Spec.Endpoints = []*externaldnsendpoint.Endpoint{} + } + + //zoneEndpoints = Records in the current dns provider zone + zoneEndpoints, err := registry.Records(ctx) + if err != nil { + return err + } + + //specEndpoints = Records that this DNSRecord expects to exist + specEndpoints, err := registry.AdjustEndpoints(dnsRecord.Spec.Endpoints) + if err != nil { + return fmt.Errorf("adjusting specEndpoints: %w", err) + } + + //statusEndpoints = Records that were created/updated by this DNSRecord last + statusEndpoints, err := registry.AdjustEndpoints(dnsRecord.Status.Endpoints) + if err != nil { + return fmt.Errorf("adjusting statusEndpoints: %w", err) + } + + //Note: All endpoint lists should be in the same provider specific format at this point + logger.V(3).Info("applyChanges", "zoneEndpoints", zoneEndpoints) + logger.V(3).Info("applyChanges", "specEndpoints", specEndpoints) + logger.V(3).Info("applyChanges", "statusEndpoints", statusEndpoints) + + plan := &externaldnsplan.Plan{ + Policies: []externaldnsplan.Policy{policy}, + Current: zoneEndpoints, + Desired: specEndpoints, + //Note: We can't just filter domains by `managedZone.Spec.DomainName` it needs to be the exact root domain for this particular record + DomainFilter: externaldnsendpoint.MatchAllDomainFilters{&rootDomainFilter}, + ManagedRecords: managedDNSRecordTypes, + ExcludeRecords: excludeDNSRecordTypes, + OwnerID: registry.OwnerID(), + } + + plan = plan.Calculate() + + if plan.Changes.HasChanges() { + logger.Info("Applying changes") + err = registry.ApplyChanges(ctx, plan.Changes) + if err != nil { + return err + } + } else { + logger.Info("All records are already up to date") + } + + return nil +} diff --git a/internal/controller/managedzone_controller.go b/internal/controller/managedzone_controller.go index 348faa3b..673c18f3 100644 --- a/internal/controller/managedzone_controller.go +++ b/internal/controller/managedzone_controller.go @@ -29,6 +29,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/log" + externaldns "sigs.k8s.io/external-dns/endpoint" "github.com/kuadrant/dns-operator/api/v1alpha1" "github.com/kuadrant/dns-operator/internal/common/conditions" @@ -162,7 +163,7 @@ func (r *ManagedZoneReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *ManagedZoneReconciler) publishManagedZone(ctx context.Context, managedZone *v1alpha1.ManagedZone) error { - dnsProvider, err := r.ProviderFactory.ProviderFor(ctx, managedZone) + dnsProvider, err := r.ProviderFactory.ProviderFor(ctx, managedZone, provider.Config{}) if err != nil { return err } @@ -184,7 +185,7 @@ func (r *ManagedZoneReconciler) deleteManagedZone(ctx context.Context, managedZo return nil } - dnsProvider, err := r.ProviderFactory.ProviderFor(ctx, managedZone) + dnsProvider, err := r.ProviderFactory.ProviderFor(ctx, managedZone, provider.Config{}) if err != nil { var reason, message string status := metav1.ConditionFalse @@ -263,7 +264,7 @@ func (r *ManagedZoneReconciler) createParentZoneNSRecord(ctx context.Context, ma ManagedZoneRef: &v1alpha1.ManagedZoneReference{ Name: parentZone.Name, }, - Endpoints: []*v1alpha1.Endpoint{ + Endpoints: []*externaldns.Endpoint{ { DNSName: recordName, Targets: recordTargets, diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go index d9c447d4..ea18ca52 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -35,6 +35,8 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + externaldnsendpoint "sigs.k8s.io/external-dns/endpoint" + externaldnsplan "sigs.k8s.io/external-dns/plan" "github.com/kuadrant/dns-operator/api/v1alpha1" "github.com/kuadrant/dns-operator/internal/health" @@ -54,14 +56,20 @@ var testEnv *envtest.Environment var ctx context.Context var cancel context.CancelFunc var dnsProviderFactory = &providerFake.Factory{ - ProviderForFunc: func(ctx context.Context, pa v1alpha1.ProviderAccessor) (provider.Provider, error) { + ProviderForFunc: func(ctx context.Context, pa v1alpha1.ProviderAccessor, c provider.Config) (provider.Provider, error) { return &providerFake.Provider{ - EnsureFunc: func(record *v1alpha1.DNSRecord, zone *v1alpha1.ManagedZone) error { - return nil + RecordsFunc: func(context.Context) ([]*externaldnsendpoint.Endpoint, error) { + return []*externaldnsendpoint.Endpoint{}, nil }, - DeleteFunc: func(record *v1alpha1.DNSRecord, zone *v1alpha1.ManagedZone) error { + ApplyChangesFunc: func(context.Context, *externaldnsplan.Changes) error { return nil }, + AdjustEndpointsFunc: func(eps []*externaldnsendpoint.Endpoint) ([]*externaldnsendpoint.Endpoint, error) { + return eps, nil + }, + GetDomainFilterFunc: func() externaldnsendpoint.DomainFilter { + return externaldnsendpoint.DomainFilter{} + }, EnsureManagedZoneFunc: func(zone *v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) { return provider.ManagedZoneOutput{}, nil }, diff --git a/internal/provider/aws/aws.go b/internal/provider/aws/aws.go index 354f8ce3..abdd77c7 100644 --- a/internal/provider/aws/aws.go +++ b/internal/provider/aws/aws.go @@ -19,7 +19,6 @@ package aws import ( "context" "fmt" - "strconv" "time" "github.com/aws/aws-sdk-go/aws" @@ -29,31 +28,36 @@ import ( "github.com/go-logr/logr" v1 "k8s.io/api/core/v1" - kerrors "k8s.io/apimachinery/pkg/util/errors" "sigs.k8s.io/controller-runtime/pkg/log" + externaldnsendpoint "sigs.k8s.io/external-dns/endpoint" + externaldnsprovider "sigs.k8s.io/external-dns/provider" + externaldnsprovideraws "sigs.k8s.io/external-dns/provider/aws" "github.com/kuadrant/dns-operator/api/v1alpha1" "github.com/kuadrant/dns-operator/internal/provider" ) const ( - ProviderSpecificRegion = "aws/region" - ProviderSpecificFailover = "aws/failover" - ProviderSpecificGeolocationSubdivisionCode = "aws/geolocation-subdivision-code" - ProviderSpecificMultiValueAnswer = "aws/multi-value-answer" - ProviderSpecificHealthCheckID = "aws/health-check-id" + providerSpecificWeight = "aws/weight" + providerSpecificGeolocationCountryCode = "aws/geolocation-country-code" + awsBatchChangeSize = 1000 + awsBatchChangeInterval = time.Second + awsEvaluateTargetHealth = true + awsPreferCNAME = false + awsZoneCacheDuration = 0 * time.Second ) type Route53DNSProvider struct { - client *InstrumentedRoute53 - logger logr.Logger - ctx context.Context + *externaldnsprovideraws.AWSProvider + awsConfig externaldnsprovideraws.AWSConfig + logger logr.Logger + route53Client *route53.Route53 + ctx context.Context } var _ provider.Provider = &Route53DNSProvider{} -func NewProviderFromSecret(ctx context.Context, s *v1.Secret) (provider.Provider, error) { - +func NewProviderFromSecret(ctx context.Context, s *v1.Secret, c provider.Config) (provider.Provider, error) { config := aws.NewConfig() sessionOpts := session.Options{ Config: *config, @@ -72,34 +76,64 @@ func NewProviderFromSecret(ctx context.Context, s *v1.Secret) (provider.Provider sess.Config.WithRegion(string(s.Data["REGION"])) } - p := &Route53DNSProvider{ - client: &InstrumentedRoute53{route53.New(sess, config)}, - logger: log.Log.WithName("aws-route53").WithValues("region", config.Region), - ctx: ctx, + route53Client := route53.New(sess, config) + + awsConfig := externaldnsprovideraws.AWSConfig{ + DomainFilter: c.DomainFilter, + ZoneIDFilter: c.ZoneIDFilter, + ZoneTypeFilter: c.ZoneTypeFilter, + ZoneTagFilter: externaldnsprovider.NewZoneTagFilter([]string{}), + BatchChangeSize: awsBatchChangeSize, + BatchChangeInterval: awsBatchChangeInterval, + EvaluateTargetHealth: awsEvaluateTargetHealth, + PreferCNAME: awsPreferCNAME, + DryRun: false, + ZoneCacheDuration: awsZoneCacheDuration, } - if err := validateServiceEndpoints(p); err != nil { - return nil, fmt.Errorf("failed to validate AWS provider service endpoints: %v", err) + awsProvider, err := externaldnsprovideraws.NewAWSProvider(awsConfig, route53Client) + if err != nil { + return nil, fmt.Errorf("unable to create aws provider: %s", err) } + p := &Route53DNSProvider{ + AWSProvider: awsProvider, + awsConfig: awsConfig, + logger: log.Log.WithName("aws-route53").WithValues("region", config.Region), + route53Client: route53Client, + ctx: ctx, + } return p, nil } -type action string +// #### External DNS Provider #### -const ( - upsertAction action = "UPSERT" - deleteAction action = "DELETE" -) +func (p *Route53DNSProvider) AdjustEndpoints(endpoints []*externaldnsendpoint.Endpoint) ([]*externaldnsendpoint.Endpoint, error) { + endpoints, err := p.AWSProvider.AdjustEndpoints(endpoints) + if err != nil { + return nil, err + } -func (p *Route53DNSProvider) Ensure(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error { - return p.change(record, managedZone, upsertAction) -} + for _, ep := range endpoints { + if prop, ok := ep.GetProviderSpecificProperty(v1alpha1.ProviderSpecificWeight); ok { + ep.DeleteProviderSpecificProperty(v1alpha1.ProviderSpecificWeight) + ep.WithProviderSpecific(providerSpecificWeight, prop) + } -func (p *Route53DNSProvider) Delete(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error { - return p.change(record, managedZone, deleteAction) + if prop, ok := ep.GetProviderSpecificProperty(v1alpha1.ProviderSpecificGeoCode); ok { + ep.DeleteProviderSpecificProperty(v1alpha1.ProviderSpecificGeoCode) + if provider.IsISO3166Alpha2Code(prop) || prop == "*" { + ep.WithProviderSpecific(providerSpecificGeolocationCountryCode, prop) + } else { + ep.WithProviderSpecific(providerSpecificGeolocationCountryCode, prop) + } + } + } + return endpoints, nil } +// #### DNS Operator Provider #### + func (p *Route53DNSProvider) EnsureManagedZone(zone *v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) { var zoneID string if zone.Spec.ID != "" { @@ -111,7 +145,7 @@ func (p *Route53DNSProvider) EnsureManagedZone(zone *v1alpha1.ManagedZone) (prov var managedZoneOutput provider.ManagedZoneOutput if zoneID != "" { - getResp, err := p.client.GetHostedZone(&route53.GetHostedZoneInput{ + getResp, err := p.route53Client.GetHostedZone(&route53.GetHostedZoneInput{ Id: &zoneID, }) if err != nil { @@ -119,7 +153,7 @@ func (p *Route53DNSProvider) EnsureManagedZone(zone *v1alpha1.ManagedZone) (prov return managedZoneOutput, err } - _, err = p.client.UpdateHostedZoneComment(&route53.UpdateHostedZoneCommentInput{ + _, err = p.route53Client.UpdateHostedZoneComment(&route53.UpdateHostedZoneCommentInput{ Comment: &zone.Spec.Description, Id: &zoneID, }) @@ -139,7 +173,7 @@ func (p *Route53DNSProvider) EnsureManagedZone(zone *v1alpha1.ManagedZone) (prov //changes to the latest version and try again callerRef := time.Now().Format("20060102150405") // Create the hosted zone - createResp, err := p.client.CreateHostedZone(&route53.CreateHostedZoneInput{ + createResp, err := p.route53Client.CreateHostedZone(&route53.CreateHostedZoneInput{ CallerReference: &callerRef, Name: &zone.Spec.DomainName, HostedZoneConfig: &route53.HostedZoneConfig{ @@ -158,7 +192,7 @@ func (p *Route53DNSProvider) EnsureManagedZone(zone *v1alpha1.ManagedZone) (prov } func (p *Route53DNSProvider) DeleteManagedZone(zone *v1alpha1.ManagedZone) error { - _, err := p.client.DeleteHostedZone(&route53.DeleteHostedZoneInput{ + _, err := p.route53Client.DeleteHostedZone(&route53.DeleteHostedZoneInput{ Id: &zone.Status.ID, }) if err != nil { @@ -168,160 +202,6 @@ func (p *Route53DNSProvider) DeleteManagedZone(zone *v1alpha1.ManagedZone) error return nil } -func (p *Route53DNSProvider) change(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone, action action) error { - // Configure records. - if len(record.Spec.Endpoints) == 0 { - return nil - } - err := p.updateRecord(record, managedZone.Status.ID, string(action)) - if err != nil { - return fmt.Errorf("failed to update record in route53 hosted zone %s: %v", managedZone.Status.ID, err) - } - switch action { - case upsertAction: - p.logger.Info("Upserted DNS record", "record", record.Spec, "hostedZoneID", managedZone.Status.ID) - case deleteAction: - p.logger.Info("Deleted DNS record", "record", record.Spec, "hostedZoneID", managedZone.Status.ID) - } - return nil -} - -func (p *Route53DNSProvider) updateRecord(record *v1alpha1.DNSRecord, zoneID, action string) error { - - if len(record.Spec.Endpoints) == 0 { - return fmt.Errorf("no endpoints") - } - - input := route53.ChangeResourceRecordSetsInput{HostedZoneId: aws.String(zoneID)} - - expectedEndpointsMap := make(map[string]struct{}) - var changes []*route53.Change - for _, endpoint := range record.Spec.Endpoints { - expectedEndpointsMap[endpoint.SetID()] = struct{}{} - change, err := p.changeForEndpoint(endpoint, action) - if err != nil { - return err - } - changes = append(changes, change) - } - - // Delete any previously published records that are no longer present in record.Spec.Endpoints - if action != string(deleteAction) { - lastPublishedEndpoints := record.Status.Endpoints - for _, endpoint := range lastPublishedEndpoints { - if _, found := expectedEndpointsMap[endpoint.SetID()]; !found { - change, err := p.changeForEndpoint(endpoint, string(deleteAction)) - if err != nil { - return err - } - changes = append(changes, change) - } - } - } - - if len(changes) == 0 { - return nil - } - input.ChangeBatch = &route53.ChangeBatch{ - Changes: changes, - } - resp, err := p.client.ChangeResourceRecordSets(&input) - if err != nil { - return fmt.Errorf("couldn't update DNS record %s in zone %s: %v", record.Name, zoneID, err) - } - p.logger.Info("Updated DNS record", "record", record, "zone", zoneID, "response", resp) - return nil -} - -func (p *Route53DNSProvider) changeForEndpoint(endpoint *v1alpha1.Endpoint, action string) (*route53.Change, error) { - if endpoint.RecordType != string(v1alpha1.ARecordType) && endpoint.RecordType != string(v1alpha1.CNAMERecordType) && endpoint.RecordType != string(v1alpha1.NSRecordType) { - return nil, fmt.Errorf("unsupported record type %s", endpoint.RecordType) - } - domain, targets := endpoint.DNSName, endpoint.Targets - if len(domain) == 0 { - return nil, fmt.Errorf("domain is required") - } - if len(targets) == 0 { - return nil, fmt.Errorf("targets is required") - } - - var resourceRecords []*route53.ResourceRecord - for _, target := range endpoint.Targets { - resourceRecords = append(resourceRecords, &route53.ResourceRecord{Value: aws.String(target)}) - } - - resourceRecordSet := &route53.ResourceRecordSet{ - Name: aws.String(endpoint.DNSName), - Type: aws.String(endpoint.RecordType), - TTL: aws.Int64(int64(endpoint.RecordTTL)), - ResourceRecords: resourceRecords, - } - - if endpoint.SetIdentifier != "" { - resourceRecordSet.SetIdentifier = aws.String(endpoint.SetIdentifier) - } - if prop, ok := endpoint.GetProviderSpecificProperty(v1alpha1.ProviderSpecificWeight); ok { - weight, err := strconv.ParseInt(prop.Value, 10, 64) - if err != nil { - p.logger.Error(err, "Failed parsing value, using weight of 0", "weight", v1alpha1.ProviderSpecificWeight, "value", prop.Value) - weight = 0 - } - resourceRecordSet.Weight = aws.Int64(weight) - } - if prop, ok := endpoint.GetProviderSpecificProperty(ProviderSpecificRegion); ok { - resourceRecordSet.Region = aws.String(prop.Value) - } - if prop, ok := endpoint.GetProviderSpecificProperty(ProviderSpecificFailover); ok { - resourceRecordSet.Failover = aws.String(prop.Value) - } - if _, ok := endpoint.GetProviderSpecificProperty(ProviderSpecificMultiValueAnswer); ok { - resourceRecordSet.MultiValueAnswer = aws.Bool(true) - } - - var geolocation = &route53.GeoLocation{} - useGeolocation := false - - if prop, ok := endpoint.GetProviderSpecificProperty(v1alpha1.ProviderSpecificGeoCode); ok { - if provider.IsISO3166Alpha2Code(prop.Value) || prop.Value == "*" { - geolocation.CountryCode = aws.String(prop.Value) - } else { - geolocation.ContinentCode = aws.String(prop.Value) - } - useGeolocation = true - } - - if geolocation.ContinentCode == nil { - if prop, ok := endpoint.GetProviderSpecificProperty(ProviderSpecificGeolocationSubdivisionCode); ok { - geolocation.SubdivisionCode = aws.String(prop.Value) - useGeolocation = true - } - } - if useGeolocation { - resourceRecordSet.GeoLocation = geolocation - } - - if prop, ok := endpoint.GetProviderSpecificProperty(ProviderSpecificHealthCheckID); ok { - resourceRecordSet.HealthCheckId = aws.String(prop.Value) - } - - change := &route53.Change{ - Action: aws.String(action), - ResourceRecordSet: resourceRecordSet, - } - return change, nil -} - -// validateServiceEndpoints validates that provider clients can communicate with -// associated API endpoints by having each client make a list/describe/get call. -func validateServiceEndpoints(provider *Route53DNSProvider) error { - var errs []error - zoneInput := route53.ListHostedZonesInput{MaxItems: aws.String("1")} - if _, err := provider.client.ListHostedZones(&zoneInput); err != nil { - errs = append(errs, fmt.Errorf("failed to list route53 hosted zones: %v", err)) - } - return kerrors.NewAggregate(errs) -} - // Register this Provider with the provider factory func init() { provider.RegisterProvider("aws", NewProviderFromSecret) diff --git a/internal/provider/factory.go b/internal/provider/factory.go index 3e3200ac..1597fcd1 100644 --- a/internal/provider/factory.go +++ b/internal/provider/factory.go @@ -18,7 +18,7 @@ var errUnsupportedProvider = fmt.Errorf("provider type given is not supported") // ProviderConstructor constructs a provider given a Secret resource and a Context. // An error will be returned if the appropriate provider is not registered. -type ProviderConstructor func(context.Context, *v1.Secret) (Provider, error) +type ProviderConstructor func(context.Context, *v1.Secret, Config) (Provider, error) var ( constructors = make(map[string]ProviderConstructor) @@ -36,7 +36,7 @@ func RegisterProvider(name string, c ProviderConstructor) { // Factory is an interface that can be used to obtain Provider implementations. // It determines which provider implementation to use by introspecting the given ProviderAccessor resource. type Factory interface { - ProviderFor(context.Context, v1alpha1.ProviderAccessor) (Provider, error) + ProviderFor(context.Context, v1alpha1.ProviderAccessor, Config) (Provider, error) } // factory is the default Factory implementation @@ -51,7 +51,7 @@ func NewFactory(c client.Client) Factory { // ProviderFor will return a Provider interface for the given ProviderAccessor secret. // If the requested ProviderAccessor secret does not exist, an error will be returned. -func (f *factory) ProviderFor(ctx context.Context, pa v1alpha1.ProviderAccessor) (Provider, error) { +func (f *factory) ProviderFor(ctx context.Context, pa v1alpha1.ProviderAccessor, c Config) (Provider, error) { providerSecret := &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: pa.GetProviderRef().Name, @@ -70,7 +70,7 @@ func (f *factory) ProviderFor(ctx context.Context, pa v1alpha1.ProviderAccessor) constructorsLock.RLock() defer constructorsLock.RUnlock() if constructor, ok := constructors[providerType]; ok { - return constructor(ctx, providerSecret) + return constructor(ctx, providerSecret, c) } return nil, fmt.Errorf("provider '%s' not registered", providerType) diff --git a/internal/provider/fake/factory.go b/internal/provider/fake/factory.go index 002f5428..6ff65a9d 100644 --- a/internal/provider/fake/factory.go +++ b/internal/provider/fake/factory.go @@ -8,11 +8,11 @@ import ( ) type Factory struct { - ProviderForFunc func(ctx context.Context, pa v1alpha1.ProviderAccessor) (provider.Provider, error) + ProviderForFunc func(ctx context.Context, pa v1alpha1.ProviderAccessor, c provider.Config) (provider.Provider, error) } var _ provider.Factory = &Factory{} -func (f *Factory) ProviderFor(ctx context.Context, pa v1alpha1.ProviderAccessor) (provider.Provider, error) { - return f.ProviderForFunc(ctx, pa) +func (f *Factory) ProviderFor(ctx context.Context, pa v1alpha1.ProviderAccessor, c provider.Config) (provider.Provider, error) { + return f.ProviderForFunc(ctx, pa, c) } diff --git a/internal/provider/fake/provider.go b/internal/provider/fake/provider.go index 8d4ee816..70a644ec 100644 --- a/internal/provider/fake/provider.go +++ b/internal/provider/fake/provider.go @@ -1,27 +1,46 @@ package fake import ( + "context" + + externaldnsendpoint "sigs.k8s.io/external-dns/endpoint" + externaldnsplan "sigs.k8s.io/external-dns/plan" + "github.com/kuadrant/dns-operator/api/v1alpha1" "github.com/kuadrant/dns-operator/internal/provider" ) type Provider struct { - EnsureFunc func(*v1alpha1.DNSRecord, *v1alpha1.ManagedZone) error - DeleteFunc func(*v1alpha1.DNSRecord, *v1alpha1.ManagedZone) error + RecordsFunc func(context.Context) ([]*externaldnsendpoint.Endpoint, error) + ApplyChangesFunc func(context.Context, *externaldnsplan.Changes) error + AdjustEndpointsFunc func([]*externaldnsendpoint.Endpoint) ([]*externaldnsendpoint.Endpoint, error) + GetDomainFilterFunc func() externaldnsendpoint.DomainFilter EnsureManagedZoneFunc func(*v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) DeleteManagedZoneFunc func(*v1alpha1.ManagedZone) error } var _ provider.Provider = &Provider{} -func (p Provider) Ensure(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error { - return p.EnsureFunc(record, managedZone) +// #### External DNS Provider #### + +func (p Provider) Records(ctx context.Context) ([]*externaldnsendpoint.Endpoint, error) { + return p.RecordsFunc(ctx) +} + +func (p Provider) ApplyChanges(ctx context.Context, changes *externaldnsplan.Changes) error { + return p.ApplyChangesFunc(ctx, changes) +} + +func (p Provider) AdjustEndpoints(endpoints []*externaldnsendpoint.Endpoint) ([]*externaldnsendpoint.Endpoint, error) { + return p.AdjustEndpointsFunc(endpoints) } -func (p Provider) Delete(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error { - return p.DeleteFunc(record, managedZone) +func (p Provider) GetDomainFilter() externaldnsendpoint.DomainFilter { + return p.GetDomainFilterFunc() } +// #### DNS Operator Provider #### + func (p Provider) EnsureManagedZone(managedZone *v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) { return p.EnsureManagedZoneFunc(managedZone) } diff --git a/internal/provider/google/google.go b/internal/provider/google/google.go index 8b9b4a02..994943cf 100644 --- a/internal/provider/google/google.go +++ b/internal/provider/google/google.go @@ -19,7 +19,6 @@ package google import ( "context" "fmt" - "net" "sort" "strconv" "strings" @@ -32,20 +31,19 @@ import ( v1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/log" + externaldnsendpoint "sigs.k8s.io/external-dns/endpoint" + externaldnsplan "sigs.k8s.io/external-dns/plan" + externaldnsprovider "sigs.k8s.io/external-dns/provider" "github.com/kuadrant/dns-operator/api/v1alpha1" "github.com/kuadrant/dns-operator/internal/provider" ) -type action string - const ( - GoogleBatchChangeSize = 1000 - GoogleBatchChangeInterval = time.Second - DryRun = false - upsertAction action = "UPSERT" - deleteAction action = "DELETE" - defaultGeo = "europe-west1" + googleRecordTTL = 300 + GoogleBatchChangeSize = 1000 + GoogleBatchChangeInterval = time.Second + DryRun = false ) // Based on the external-dns google provider https://github.com/kubernetes-sigs/external-dns/blob/master/provider/google/google.go @@ -135,6 +133,12 @@ type GoogleDNSProvider struct { batchChangeSize int // Interval between batch updates. batchChangeInterval time.Duration + // only consider hosted zones managing domains ending in this suffix + domainFilter externaldnsendpoint.DomainFilter + // filter for zones based on visibility + zoneTypeFilter externaldnsprovider.ZoneTypeFilter + // only consider hosted zones ending with this zone id + zoneIDFilter externaldnsprovider.ZoneIDFilter // A client for managing resource record sets resourceRecordSetsClient resourceRecordSetsClientInterface // A client for managing hosted zones @@ -147,7 +151,7 @@ type GoogleDNSProvider struct { var _ provider.Provider = &GoogleDNSProvider{} -func NewProviderFromSecret(ctx context.Context, s *v1.Secret) (provider.Provider, error) { +func NewProviderFromSecret(ctx context.Context, s *v1.Secret, c provider.Config) (provider.Provider, error) { if string(s.Data["GOOGLE"]) == "" || string(s.Data["PROJECT_ID"]) == "" { return nil, fmt.Errorf("GCP Provider credentials is empty") @@ -166,6 +170,9 @@ func NewProviderFromSecret(ctx context.Context, s *v1.Secret) (provider.Provider dryRun: DryRun, batchChangeSize: GoogleBatchChangeSize, batchChangeInterval: GoogleBatchChangeInterval, + domainFilter: c.DomainFilter, + zoneTypeFilter: c.ZoneTypeFilter, + zoneIDFilter: c.ZoneIDFilter, resourceRecordSetsClient: resourceRecordSetsService{dnsClient.ResourceRecordSets}, managedZonesClient: managedZonesService{dnsClient.ManagedZones}, changesClient: changesService{dnsClient.Changes}, @@ -175,168 +182,176 @@ func NewProviderFromSecret(ctx context.Context, s *v1.Secret) (provider.Provider return p, nil } -// ManagedZones +// #### External DNS Provider #### -func (g *GoogleDNSProvider) DeleteManagedZone(managedZone *v1alpha1.ManagedZone) error { - return g.managedZonesClient.Delete(g.project, managedZone.Status.ID).Do() -} +// Zones returns the list of hosted zones. +func (p *GoogleDNSProvider) Zones(ctx context.Context) (map[string]*dnsv1.ManagedZone, error) { + zones := make(map[string]*dnsv1.ManagedZone) -func (g *GoogleDNSProvider) EnsureManagedZone(managedZone *v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) { - var zoneID string + f := func(resp *dnsv1.ManagedZonesListResponse) error { + for _, zone := range resp.ManagedZones { + if zone.PeeringConfig == nil { + if p.domainFilter.Match(zone.DnsName) && p.zoneTypeFilter.Match(zone.Visibility) && (p.zoneIDFilter.Match(fmt.Sprintf("%v", zone.Id)) || p.zoneIDFilter.Match(fmt.Sprintf("%v", zone.Name))) { + zones[zone.Name] = zone + p.logger.Info(fmt.Sprintf("Matched %s (zone: %s) (visibility: %s)", zone.DnsName, zone.Name, zone.Visibility)) + } else { + p.logger.Info(fmt.Sprintf("Filtered %s (zone: %s) (visibility: %s)", zone.DnsName, zone.Name, zone.Visibility)) + } + } else { + p.logger.Info(fmt.Sprintf("Filtered peering zone %s (zone: %s) (visibility: %s)", zone.DnsName, zone.Name, zone.Visibility)) + } + } - if managedZone.Spec.ID != "" { - zoneID = managedZone.Spec.ID - } else { - zoneID = managedZone.Status.ID + return nil } - if zoneID != "" { - //Get existing managed zone - return g.getManagedZone(zoneID) + p.logger.Info(fmt.Sprintf("Matching zones against domain filters: %v", p.domainFilter)) + if err := p.managedZonesClient.List(p.project).Pages(ctx, f); err != nil { + return nil, err } - //Create new managed zone - return g.createManagedZone(managedZone) -} -func (g *GoogleDNSProvider) createManagedZone(managedZone *v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) { - zoneID := strings.Replace(managedZone.Spec.DomainName, ".", "-", -1) - zone := dnsv1.ManagedZone{ - Name: zoneID, - DnsName: ensureTrailingDot(managedZone.Spec.DomainName), - Description: managedZone.Spec.Description, + if len(zones) == 0 { + p.logger.Info(fmt.Sprintf("No zones in the project, %s, match domain filters: %v", p.project, p.domainFilter)) } - mz, err := g.managedZonesClient.Create(g.project, &zone).Do() - if err != nil { - return provider.ManagedZoneOutput{}, err + + for _, zone := range zones { + p.logger.Info(fmt.Sprintf("Considering zone: %s (domain: %s)", zone.Name, zone.DnsName)) } - return g.toManagedZoneOutput(mz) + + return zones, nil } -func (g *GoogleDNSProvider) getManagedZone(zoneID string) (provider.ManagedZoneOutput, error) { - mz, err := g.managedZonesClient.Get(g.project, zoneID).Do() +// Records returns records from the provider in google specific format +func (p *GoogleDNSProvider) Records(ctx context.Context) (endpoints []*externaldnsendpoint.Endpoint, _ error) { + zones, err := p.Zones(ctx) if err != nil { - return provider.ManagedZoneOutput{}, err + return nil, err } - return g.toManagedZoneOutput(mz) -} - -func (g *GoogleDNSProvider) toManagedZoneOutput(mz *dnsv1.ManagedZone) (provider.ManagedZoneOutput, error) { - var managedZoneOutput provider.ManagedZoneOutput - zoneID := mz.Name - var nameservers []*string - for i := range mz.NameServers { - nameservers = append(nameservers, &mz.NameServers[i]) + var records []*dnsv1.ResourceRecordSet + f := func(resp *dnsv1.ResourceRecordSetsListResponse) error { + for _, r := range resp.Rrsets { + if !p.SupportedRecordType(r.Type) { + continue + } + records = append(records, r) + } + return nil } - managedZoneOutput.ID = zoneID - managedZoneOutput.NameServers = nameservers - currentRecords, err := g.getResourceRecordSets(g.ctx, zoneID) - if err != nil { - return managedZoneOutput, err + for _, z := range zones { + if err := p.resourceRecordSetsClient.List(p.project, z.Name).Pages(ctx, f); err != nil { + return nil, err + } } - managedZoneOutput.RecordCount = int64(len(currentRecords)) - return managedZoneOutput, nil + return endpointsFromResourceRecordSets(records), nil } -//DNSRecords +func (p *GoogleDNSProvider) ApplyChanges(ctx context.Context, changes *externaldnsplan.Changes) error { + change := &dnsv1.Change{} + + change.Additions = append(change.Additions, p.newFilteredRecords(changes.Create)...) -func (g *GoogleDNSProvider) Ensure(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error { - return g.updateRecord(record, managedZone.Status.ID, upsertAction) + change.Additions = append(change.Additions, p.newFilteredRecords(changes.UpdateNew)...) + change.Deletions = append(change.Deletions, p.newFilteredRecords(changes.UpdateOld)...) + + change.Deletions = append(change.Deletions, p.newFilteredRecords(changes.Delete)...) + + return p.submitChange(ctx, change) } -func (g *GoogleDNSProvider) Delete(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error { - return g.updateRecord(record, managedZone.Status.ID, deleteAction) +// AdjustEndpoints takes source endpoints and translates them to a google specific format +func (p *GoogleDNSProvider) AdjustEndpoints(endpoints []*externaldnsendpoint.Endpoint) ([]*externaldnsendpoint.Endpoint, error) { + return endpointsToGoogleFormat(endpoints), nil } -func (g *GoogleDNSProvider) updateRecord(dnsRecord *v1alpha1.DNSRecord, zoneID string, action action) error { - // When updating records the Google DNS API expects you to delete any existing record and add the new one as part of - // the same change request. The record to be deleted must match exactly what currently exists in the provider or the - // change request will fail. To make sure we can always remove the records, we first get all records that exist in - // the zone and build up the deleting list from `dnsRecord.Status` but use the most recent version of it retrieved - // from the provider in the change request. - currentRecords, err := g.getResourceRecordSets(g.ctx, zoneID) - if err != nil { - return err - } - currentRecordsMap := make(map[string]*dnsv1.ResourceRecordSet) - for _, record := range currentRecords { - currentRecordsMap[record.Name] = record - } - statusRecords := toResourceRecordSets(dnsRecord.Status.Endpoints) - statusRecordsMap := make(map[string]*dnsv1.ResourceRecordSet) - for _, record := range statusRecords { - statusRecordsMap[record.Name] = record - } +func (p *GoogleDNSProvider) GetDomainFilter() externaldnsendpoint.DomainFilter { + return externaldnsendpoint.DomainFilter{} +} - var deletingRecords []*dnsv1.ResourceRecordSet - for name := range statusRecordsMap { - if record, ok := currentRecordsMap[name]; ok { - deletingRecords = append(deletingRecords, record) - } +// SupportedRecordType returns true if the record type is supported by the provider +func (p *GoogleDNSProvider) SupportedRecordType(recordType string) bool { + switch recordType { + case "MX": + return true + default: + return externaldnsprovider.SupportedRecordType(recordType) } - addingRecords := toResourceRecordSets(dnsRecord.Spec.Endpoints) +} - g.logger.V(1).Info("updateRecord", "currentRecords", currentRecords, "deletingRecords", deletingRecords, "addingRecords", addingRecords) +// newFilteredRecords returns a collection of RecordSets based on the given endpoints and domainFilter. +func (p *GoogleDNSProvider) newFilteredRecords(endpoints []*externaldnsendpoint.Endpoint) []*dnsv1.ResourceRecordSet { + records := []*dnsv1.ResourceRecordSet{} - change := &dnsv1.Change{} - if action == deleteAction { - change.Deletions = deletingRecords - } else { - change.Deletions = deletingRecords - change.Additions = addingRecords + for _, endpoint := range endpoints { + if p.domainFilter.Match(endpoint.DNSName) { + records = append(records, newRecord(endpoint)) + } } - return g.submitChange(change, zoneID) + return records } -func (g *GoogleDNSProvider) submitChange(change *dnsv1.Change, zone string) error { +// submitChange takes a zone and a Change and sends it to Google. +func (p *GoogleDNSProvider) submitChange(ctx context.Context, change *dnsv1.Change) error { if len(change.Additions) == 0 && len(change.Deletions) == 0 { - g.logger.Info("All records are already up to date") + p.logger.Info("All records are already up to date") return nil } - for batch, c := range g.batchChange(change, g.batchChangeSize) { - g.logger.V(1).Info("Change zone", "zone", zone, "batch", batch) - for _, del := range c.Deletions { - g.logger.V(1).Info("Del records", "name", del.Name, "type", del.Type, "Rrdatas", - del.Rrdatas, "RoutingPolicy", del.RoutingPolicy, "ttl", del.Ttl) - } - for _, add := range c.Additions { - g.logger.V(1).Info("Add records", "name", add.Name, "type", add.Type, "Rrdatas", - add.Rrdatas, "RoutingPolicy", add.RoutingPolicy, "ttl", add.Ttl) - } - if g.dryRun { - continue - } + zones, err := p.Zones(ctx) + if err != nil { + return err + } + + // separate into per-zone change sets to be passed to the API. + changes := separateChange(zones, change) + + for zone, change := range changes { + for batch, c := range batchChange(change, p.batchChangeSize) { + p.logger.Info(fmt.Sprintf("Change zone: %v batch #%d", zone, batch)) + for _, del := range c.Deletions { + p.logger.Info(fmt.Sprintf("Del records: %s %s %s %d", del.Name, del.Type, del.Rrdatas, del.Ttl)) + } + for _, add := range c.Additions { + p.logger.Info(fmt.Sprintf("Add records: %s %s %s %d", add.Name, add.Type, add.Rrdatas, add.Ttl)) + } + + if p.dryRun { + continue + } - if _, err := g.changesClient.Create(g.project, zone, c).Do(); err != nil { - return err + if _, err := p.changesClient.Create(p.project, zone, c).Do(); err != nil { + return err + } + + time.Sleep(p.batchChangeInterval) } - time.Sleep(g.batchChangeInterval) } + return nil } -func (g *GoogleDNSProvider) batchChange(change *dnsv1.Change, batchSize int) []*dnsv1.Change { +// batchChange separates a zone in multiple transaction. +func batchChange(change *dnsv1.Change, batchSize int) []*dnsv1.Change { changes := []*dnsv1.Change{} if batchSize == 0 { return append(changes, change) } - type dnsv1Change struct { + type dnsChange struct { additions []*dnsv1.ResourceRecordSet deletions []*dnsv1.ResourceRecordSet } - changesByName := map[string]*dnsv1Change{} + changesByName := map[string]*dnsChange{} for _, a := range change.Additions { change, ok := changesByName[a.Name] if !ok { - change = &dnsv1Change{} + change = &dnsChange{} changesByName[a.Name] = change } @@ -346,7 +361,7 @@ func (g *GoogleDNSProvider) batchChange(change *dnsv1.Change, batchSize int) []* for _, a := range change.Deletions { change, ok := changesByName[a.Name] if !ok { - change = &dnsv1Change{} + change = &dnsChange{} changesByName[a.Name] = change } @@ -367,8 +382,7 @@ func (g *GoogleDNSProvider) batchChange(change *dnsv1.Change, batchSize int) []* totalChangesByName := len(c.additions) + len(c.deletions) if totalChangesByName > batchSize { - g.logger.V(1).Info("Total changes for %s exceeds max batch size of %d, total changes: %d", name, - batchSize, totalChangesByName) + log.Log.Info(fmt.Sprintf("Total changes for %s exceeds max batch size of %d, total changes: %d", name, batchSize, totalChangesByName)) continue } @@ -391,110 +405,307 @@ func (g *GoogleDNSProvider) batchChange(change *dnsv1.Change, batchSize int) []* return changes } -// getResourceRecordSets returns the records for a managed zone of the currently configured provider. -func (g *GoogleDNSProvider) getResourceRecordSets(ctx context.Context, zoneID string) ([]*dnsv1.ResourceRecordSet, error) { - var records []*dnsv1.ResourceRecordSet +// separateChange separates a multi-zone change into a single change per zone. +func separateChange(zones map[string]*dnsv1.ManagedZone, change *dnsv1.Change) map[string]*dnsv1.Change { + changes := make(map[string]*dnsv1.Change) + zoneNameIDMapper := externaldnsprovider.ZoneIDName{} + for _, z := range zones { + zoneNameIDMapper[z.Name] = z.DnsName + changes[z.Name] = &dnsv1.Change{ + Additions: []*dnsv1.ResourceRecordSet{}, + Deletions: []*dnsv1.ResourceRecordSet{}, + } + } + for _, a := range change.Additions { + if zoneName, _ := zoneNameIDMapper.FindZone(externaldnsprovider.EnsureTrailingDot(a.Name)); zoneName != "" { + changes[zoneName].Additions = append(changes[zoneName].Additions, a) + } else { + log.Log.Info(fmt.Sprintf("No matching zone for record addition: %s %s %s %d", a.Name, a.Type, a.Rrdatas, a.Ttl)) + } + } - f := func(resp *dnsv1.ResourceRecordSetsListResponse) error { - records = append(records, resp.Rrsets...) - return nil + for _, d := range change.Deletions { + if zoneName, _ := zoneNameIDMapper.FindZone(externaldnsprovider.EnsureTrailingDot(d.Name)); zoneName != "" { + changes[zoneName].Deletions = append(changes[zoneName].Deletions, d) + } else { + log.Log.Info(fmt.Sprintf("No matching zone for record deletion: %s %s %s %d", d.Name, d.Type, d.Rrdatas, d.Ttl)) + } } - if err := g.resourceRecordSetsClient.List(g.project, zoneID).Pages(ctx, f); err != nil { - return nil, err + // separating a change could lead to empty sub changes, remove them here. + for zone, change := range changes { + if len(change.Additions) == 0 && len(change.Deletions) == 0 { + delete(changes, zone) + } } - return records, nil + return changes } -// toResourceRecordSets converts a list of endpoints into `ResourceRecordSet` resources. -func toResourceRecordSets(allEndpoints []*v1alpha1.Endpoint) []*dnsv1.ResourceRecordSet { - var records []*dnsv1.ResourceRecordSet +// endpointsFromResourceRecordSets converts a list of `ResourceRecordSet` into endpoints (google format). +func endpointsFromResourceRecordSets(resourceRecordSets []*dnsv1.ResourceRecordSet) []*externaldnsendpoint.Endpoint { + var endpoints []*externaldnsendpoint.Endpoint - // Google DNS requires a record to be created per `dnsName`, so the first thing we need to do is group all the - // endpoints with the same dnsName together. - endpointMap := make(map[string][]*v1alpha1.Endpoint) - for _, ep := range allEndpoints { - endpointMap[ep.DNSName] = append(endpointMap[ep.DNSName], ep) + for _, rrs := range resourceRecordSets { + if rrs.RoutingPolicy != nil { + endpoint := externaldnsendpoint.NewEndpointWithTTL(rrs.Name, rrs.Type, externaldnsendpoint.TTL(rrs.Ttl), []string{}...) + + if rrs.RoutingPolicy.Wrr != nil { + endpoint.WithProviderSpecific("routingpolicy", "weighted") + for i := range rrs.RoutingPolicy.Wrr.Items { + weight := strconv.FormatFloat(rrs.RoutingPolicy.Wrr.Items[i].Weight, 'f', -1, 64) + for idx := range rrs.RoutingPolicy.Wrr.Items[i].Rrdatas { + target := strings.TrimSuffix(rrs.RoutingPolicy.Wrr.Items[i].Rrdatas[idx], ".") + endpoint.Targets = append(endpoint.Targets, target) + endpoint.WithProviderSpecific(target, weight) + } + } + } else if rrs.RoutingPolicy.Geo != nil { + endpoint.WithProviderSpecific("routingpolicy", "geo") + for i := range rrs.RoutingPolicy.Geo.Items { + location := rrs.RoutingPolicy.Geo.Items[i].Location + for idx := range rrs.RoutingPolicy.Geo.Items[i].Rrdatas { + target := strings.TrimSuffix(rrs.RoutingPolicy.Geo.Items[i].Rrdatas[idx], ".") + endpoint.Targets = append(endpoint.Targets, target) + endpoint.WithProviderSpecific(target, location) + } + } + } else { + //Not good !! + continue + } + endpoints = append(endpoints, endpoint) + } else { + endpoints = append(endpoints, externaldnsendpoint.NewEndpointWithTTL(rrs.Name, rrs.Type, externaldnsendpoint.TTL(rrs.Ttl), rrs.Rrdatas...)) + } } + return endpoints +} + +// endpointsToProviderFormat converts a list of endpoints into a google specific format. +func endpointsToGoogleFormat(eps []*externaldnsendpoint.Endpoint) []*externaldnsendpoint.Endpoint { + endpointMap := make(map[string][]*externaldnsendpoint.Endpoint) + for i := range eps { + endpointMap[eps[i].DNSName] = append(endpointMap[eps[i].DNSName], eps[i]) + } + + translatedEndpoints := []*externaldnsendpoint.Endpoint{} + for dnsName, endpoints := range endpointMap { // A set of endpoints belonging to the same group(`dnsName`) must always be of the same type, have the same ttl // and contain the same rrdata (weighted or geo), so we can just get that from the first endpoint in the list. ttl := int64(endpoints[0].RecordTTL) recordType := endpoints[0].RecordType - _, weighted := endpoints[0].GetProviderSpecificProperty(v1alpha1.ProviderSpecificWeight) - _, geoCode := endpoints[0].GetProviderSpecificProperty(v1alpha1.ProviderSpecificGeoCode) + _, isWeighted := endpoints[0].GetProviderSpecificProperty(v1alpha1.ProviderSpecificWeight) + _, isGeo := endpoints[0].GetProviderSpecificProperty(v1alpha1.ProviderSpecificGeoCode) - record := &dnsv1.ResourceRecordSet{ - Name: ensureTrailingDot(dnsName), - Ttl: ttl, - Type: recordType, + if !isGeo && !isWeighted { + //ToDO DO we need to worry about there being more than one here? + translatedEndpoints = append(translatedEndpoints, endpoints[0]) + continue } - if weighted { - record.RoutingPolicy = &dnsv1.RRSetRoutingPolicy{ - Wrr: &dnsv1.RRSetRoutingPolicyWrrPolicy{}, - } - } else if geoCode { - record.RoutingPolicy = &dnsv1.RRSetRoutingPolicy{ - Geo: &dnsv1.RRSetRoutingPolicyGeoPolicy{}, - } + + translatedEndpoint := externaldnsendpoint.NewEndpointWithTTL(dnsName, recordType, externaldnsendpoint.TTL(ttl)) + + if isGeo { + translatedEndpoint.WithProviderSpecific("routingpolicy", "geo") + } else if isWeighted { + translatedEndpoint.WithProviderSpecific("routingpolicy", "weighted") } + //ToDo this has the potential to add duplicates for _, ep := range endpoints { - targets := make([]string, len(ep.Targets)) - copy(targets, ep.Targets) - if ep.RecordType == string(v1alpha1.CNAMERecordType) { - targets[0] = ensureTrailingDot(targets[0]) + for _, t := range ep.Targets { + if isGeo { + geo, _ := ep.GetProviderSpecificProperty(v1alpha1.ProviderSpecificGeoCode) + if geo == "*" { + continue + } + translatedEndpoint.WithProviderSpecific(t, geo) + } else if isWeighted { + weight, _ := ep.GetProviderSpecificProperty(v1alpha1.ProviderSpecificWeight) + translatedEndpoint.WithProviderSpecific(t, weight) + } + translatedEndpoint.Targets = append(translatedEndpoint.Targets, t) } + } + + translatedEndpoints = append(translatedEndpoints, translatedEndpoint) + } + + return translatedEndpoints +} - if !weighted && !geoCode { - record.Rrdatas = targets +// resourceRecordSetFromEndpoint converts an endpoint(google format) into a `ResourceRecordSet`. +func resourceRecordSetFromEndpoint(ep *externaldnsendpoint.Endpoint) *dnsv1.ResourceRecordSet { + + // no annotation results in a Ttl of 0, default to 300 for backwards-compatibility + var ttl int64 = googleRecordTTL + if ep.RecordTTL.IsConfigured() { + ttl = int64(ep.RecordTTL) + } + + rrs := &dnsv1.ResourceRecordSet{ + Name: externaldnsprovider.EnsureTrailingDot(ep.DNSName), + Ttl: ttl, + Type: ep.RecordType, + } + + if rp, ok := ep.GetProviderSpecificProperty("routingpolicy"); ok { + if rp == "geo" { + rrs.RoutingPolicy = &dnsv1.RRSetRoutingPolicy{ + Geo: &dnsv1.RRSetRoutingPolicyGeoPolicy{}, } - if weighted { - weightProp, _ := ep.GetProviderSpecificProperty(v1alpha1.ProviderSpecificWeight) - weight, err := strconv.ParseFloat(weightProp.Value, 64) - if err != nil { - weight = 0 + //Map location to targets, can ony have one location the same + targetMap := make(map[string][]string) + for i := range ep.Targets { + if location, ok := ep.GetProviderSpecificProperty(ep.Targets[i]); ok { + targetMap[location] = append(targetMap[location], externaldnsprovider.EnsureTrailingDot(ep.Targets[i])) } - item := &dnsv1.RRSetRoutingPolicyWrrPolicyWrrPolicyItem{ - Rrdatas: targets, - Weight: weight, + } + for l, t := range targetMap { + item := &dnsv1.RRSetRoutingPolicyGeoPolicyGeoPolicyItem{ + Location: l, + Rrdatas: t, } - record.RoutingPolicy.Wrr.Items = append(record.RoutingPolicy.Wrr.Items, item) + rrs.RoutingPolicy.Geo.Items = append(rrs.RoutingPolicy.Geo.Items, item) } - if geoCode { - geoCodeProp, _ := ep.GetProviderSpecificProperty(v1alpha1.ProviderSpecificGeoCode) - geoCodeValue := geoCodeProp.Value - targetIsDefaultGroup := strings.HasPrefix(ep.Targets[0], v1alpha1.DefaultGeo) - // GCP doesn't accept * as value for default geolocations like AWS does. - // To ensure the dns chain doesn't break if a * is given we map the value to europe-west1 instead - // We cant drop the record as the chain will break - if geoCodeValue == "*" { - if !targetIsDefaultGroup { - continue + } else if rp == "weighted" { + rrs.RoutingPolicy = &dnsv1.RRSetRoutingPolicy{ + Wrr: &dnsv1.RRSetRoutingPolicyWrrPolicy{}, + } + + for i := range ep.Targets { + if weightStr, ok := ep.GetProviderSpecificProperty(ep.Targets[i]); ok { + weight, err := strconv.ParseFloat(weightStr, 64) + if err != nil { + weight = 0.0 } - geoCodeValue = defaultGeo - } - item := &dnsv1.RRSetRoutingPolicyGeoPolicyGeoPolicyItem{ - Location: geoCodeValue, - Rrdatas: targets, + item := &dnsv1.RRSetRoutingPolicyWrrPolicyWrrPolicyItem{ + Rrdatas: []string{externaldnsprovider.EnsureTrailingDot(ep.Targets[i])}, + Weight: weight, + } + rrs.RoutingPolicy.Wrr.Items = append(rrs.RoutingPolicy.Wrr.Items, item) } - record.RoutingPolicy.Geo.Items = append(record.RoutingPolicy.Geo.Items, item) } } - records = append(records, record) + + return rrs } - return records + + targets := make([]string, len(ep.Targets)) + copy(targets, []string(ep.Targets)) + if ep.RecordType == externaldnsendpoint.RecordTypeCNAME { + if len(targets) > 0 { + targets[0] = externaldnsprovider.EnsureTrailingDot(targets[0]) + } + } + + if ep.RecordType == externaldnsendpoint.RecordTypeMX { + for i, mxRecord := range ep.Targets { + targets[i] = externaldnsprovider.EnsureTrailingDot(mxRecord) + } + } + + if ep.RecordType == externaldnsendpoint.RecordTypeSRV { + for i, srvRecord := range ep.Targets { + targets[i] = externaldnsprovider.EnsureTrailingDot(srvRecord) + } + } + + rrs.Rrdatas = targets + + return rrs +} + +// newRecord returns a RecordSet based on the given endpoint(google format). +func newRecord(ep *externaldnsendpoint.Endpoint) *dnsv1.ResourceRecordSet { + return resourceRecordSetFromEndpoint(ep) +} + +// #### DNS Operator Provider #### + +func (p *GoogleDNSProvider) EnsureManagedZone(managedZone *v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) { + var zoneID string + + if managedZone.Spec.ID != "" { + zoneID = managedZone.Spec.ID + } else { + zoneID = managedZone.Status.ID + } + + if zoneID != "" { + //Get existing managed zone + return p.getManagedZone(zoneID) + } + //Create new managed zone + return p.createManagedZone(managedZone) +} + +func (p *GoogleDNSProvider) DeleteManagedZone(managedZone *v1alpha1.ManagedZone) error { + return p.managedZonesClient.Delete(p.project, managedZone.Status.ID).Do() } -// ensureTrailingDot ensures that the hostname receives a trailing dot if it hasn't already. -func ensureTrailingDot(hostname string) string { - if net.ParseIP(hostname) != nil { - return hostname +// ManagedZones + +func (p *GoogleDNSProvider) createManagedZone(managedZone *v1alpha1.ManagedZone) (provider.ManagedZoneOutput, error) { + zoneID := strings.Replace(managedZone.Spec.DomainName, ".", "-", -1) + zone := dnsv1.ManagedZone{ + Name: zoneID, + DnsName: externaldnsprovider.EnsureTrailingDot(managedZone.Spec.DomainName), + Description: managedZone.Spec.Description, } + mz, err := p.managedZonesClient.Create(p.project, &zone).Do() + if err != nil { + return provider.ManagedZoneOutput{}, err + } + return p.toManagedZoneOutput(mz) +} - return strings.TrimSuffix(hostname, ".") + "." +func (p *GoogleDNSProvider) getManagedZone(zoneID string) (provider.ManagedZoneOutput, error) { + mz, err := p.managedZonesClient.Get(p.project, zoneID).Do() + if err != nil { + return provider.ManagedZoneOutput{}, err + } + return p.toManagedZoneOutput(mz) +} + +func (p *GoogleDNSProvider) toManagedZoneOutput(mz *dnsv1.ManagedZone) (provider.ManagedZoneOutput, error) { + var managedZoneOutput provider.ManagedZoneOutput + + zoneID := mz.Name + var nameservers []*string + for i := range mz.NameServers { + nameservers = append(nameservers, &mz.NameServers[i]) + } + managedZoneOutput.ID = zoneID + managedZoneOutput.NameServers = nameservers + + currentRecords, err := p.getResourceRecordSets(p.ctx, zoneID) + if err != nil { + return managedZoneOutput, err + } + managedZoneOutput.RecordCount = int64(len(currentRecords)) + + return managedZoneOutput, nil +} + +// ToDo Can be replaced with a call to Records if/when we update that to optionally accept a zone id +// getResourceRecordSets returns the records for a managed zone of the currently configured provider. +func (p *GoogleDNSProvider) getResourceRecordSets(ctx context.Context, zoneID string) ([]*dnsv1.ResourceRecordSet, error) { + var records []*dnsv1.ResourceRecordSet + + f := func(resp *dnsv1.ResourceRecordSetsListResponse) error { + records = append(records, resp.Rrsets...) + return nil + } + + if err := p.resourceRecordSetsClient.List(p.project, zoneID).Pages(ctx, f); err != nil { + return nil, err + } + + return records, nil } // Register this Provider with the provider factory diff --git a/internal/provider/google/google_test.go b/internal/provider/google/google_test.go index ad3a215e..aa270a9d 100644 --- a/internal/provider/google/google_test.go +++ b/internal/provider/google/google_test.go @@ -12,7 +12,9 @@ import ( "github.com/aws/aws-sdk-go/aws" dnsv1 "google.golang.org/api/dns/v1" - "github.com/kuadrant/dns-operator/api/v1alpha1" + "k8s.io/apimachinery/pkg/api/equality" + externaldnsendpoint "sigs.k8s.io/external-dns/endpoint" + "github.com/kuadrant/dns-operator/internal/provider" ) @@ -131,44 +133,262 @@ func TestGoogleDNSProvider_toManagedZoneOutput(t *testing.T) { } } -func Test_toResourceRecordSets(t *testing.T) { +type MockResourceRecordSetsListCall struct { + PagesFunc func(ctx context.Context, f func(*dnsv1.ResourceRecordSetsListResponse) error) error +} + +func (m *MockResourceRecordSetsListCall) Pages(ctx context.Context, f func(*dnsv1.ResourceRecordSetsListResponse) error) error { + return m.PagesFunc(ctx, f) + +} + +type MockResourceRecordSetsClient struct { + ListFunc func(project string, managedZone string) resourceRecordSetsListCallInterface +} + +func (m *MockResourceRecordSetsClient) List(project string, managedZone string) resourceRecordSetsListCallInterface { + + return m.ListFunc(project, managedZone) + +} + +func sorted(endpoints []*externaldnsendpoint.Endpoint) { + sort.Slice(endpoints, func(i, j int) bool { + return endpoints[i].DNSName < endpoints[j].DNSName + }) +} + +func Test_endpointsFromResourceRecordSets(t *testing.T) { type args struct { - allEndpoints []*v1alpha1.Endpoint + resourceRecordSets []*dnsv1.ResourceRecordSet } tests := []struct { name string args args - want []*dnsv1.ResourceRecordSet + want []*externaldnsendpoint.Endpoint }{ { - name: "Successful test Geo & weight", + name: "test CNAME with geo and multiple targets", args: args{ - allEndpoints: []*v1alpha1.Endpoint{ + resourceRecordSets: []*dnsv1.ResourceRecordSet{ { - DNSName: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", - RecordType: "A", - RecordTTL: 60, - Targets: v1alpha1.Targets{ + Name: "lb-4ej5le.unittest.google.hcpapps.net.", + RoutingPolicy: &dnsv1.RRSetRoutingPolicy{ + Geo: &dnsv1.RRSetRoutingPolicyGeoPolicy{ + EnableFencing: false, + Items: []*dnsv1.RRSetRoutingPolicyGeoPolicyGeoPolicyItem{ + { + Location: "europe-west1", + Rrdatas: []string{ + "europe-west1.lb-4ej5le.unittest.google.hcpapps.net.", + }, + }, + { + Location: "us-east1", + Rrdatas: []string{ + "us-east1.lb-4ej5le.unittest.google.hcpapps.net.", + }, + }, + }, + }, + }, + Ttl: 300, + Type: "CNAME", + }, + }, + }, + want: []*externaldnsendpoint.Endpoint{ + { + DNSName: "lb-4ej5le.unittest.google.hcpapps.net", + RecordType: "CNAME", + RecordTTL: 300, + Targets: externaldnsendpoint.Targets{ + "europe-west1.lb-4ej5le.unittest.google.hcpapps.net", + "us-east1.lb-4ej5le.unittest.google.hcpapps.net", + }, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "geo", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "europe-west1.lb-4ej5le.unittest.google.hcpapps.net", + Value: "europe-west1", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "us-east1.lb-4ej5le.unittest.google.hcpapps.net", + Value: "us-east1", + }, + }, + }, + }, + }, + { + name: "test CNAME with weights and multiple targets", + args: args{ + resourceRecordSets: []*dnsv1.ResourceRecordSet{ + { + Name: "default.lb-4ej5le.unittest.google.hcpapps.net.", + RoutingPolicy: &dnsv1.RRSetRoutingPolicy{ + Wrr: &dnsv1.RRSetRoutingPolicyWrrPolicy{ + Items: []*dnsv1.RRSetRoutingPolicyWrrPolicyWrrPolicyItem{ + { + Rrdatas: []string{ + "2c71gf.lb-4ej5le.unittest.google.hcpapps.net.", + }, + Weight: 120, + }, + { + Rrdatas: []string{ + "lrnse3.lb-4ej5le.unittest.google.hcpapps.net.", + }, + Weight: 120, + }, + }, + }, + }, + Ttl: 60, + Type: "CNAME", + }, + }, + }, + want: []*externaldnsendpoint.Endpoint{ + { + DNSName: "default.lb-4ej5le.unittest.google.hcpapps.net", + RecordType: "CNAME", + RecordTTL: 60, + Targets: externaldnsendpoint.Targets{ + "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + "lrnse3.lb-4ej5le.unittest.google.hcpapps.net", + }, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "weighted", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + Value: "120", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "lrnse3.lb-4ej5le.unittest.google.hcpapps.net", + Value: "120", + }, + }, + }, + }, + }, + { + name: "test A record", + args: args{ + resourceRecordSets: []*dnsv1.ResourceRecordSet{ + { + Name: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net.", + Rrdatas: []string{ "0.0.0.0", }, - ProviderSpecific: v1alpha1.ProviderSpecific{}, - SetIdentifier: "", + Ttl: 60, + Type: "A", + }, + }, + }, + want: []*externaldnsendpoint.Endpoint{ + { + DNSName: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + RecordType: "A", + RecordTTL: 60, + Targets: externaldnsendpoint.Targets{ + "0.0.0.0", }, + SetIdentifier: "", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := endpointsFromResourceRecordSets(tt.args.resourceRecordSets); !equality.Semantic.DeepEqual(got, tt.want) { + t.Errorf("endpointsFromResourceRecordSets() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_endpointsToGoogleFormat(t *testing.T) { + type args struct { + endpoints []*externaldnsendpoint.Endpoint + } + tests := []struct { + name string + args args + want []*externaldnsendpoint.Endpoint + }{ + { + name: "multiple weighted records", + args: args{ + endpoints: []*externaldnsendpoint.Endpoint{ { - DNSName: "europe-west1.lb-4ej5le.unittest.google.hcpapps.net", + DNSName: "default.lb-4ej5le.unittest.google.hcpapps.net", RecordType: "CNAME", SetIdentifier: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", RecordTTL: 60, - Targets: v1alpha1.Targets{ + Targets: externaldnsendpoint.Targets{ "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", }, - ProviderSpecific: v1alpha1.ProviderSpecific{ - v1alpha1.ProviderSpecificProperty{ + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ Name: "weight", - Value: "60", + Value: "120", }, }, }, + { + DNSName: "default.lb-4ej5le.unittest.google.hcpapps.net", + RecordType: "CNAME", + SetIdentifier: "lrnse3.lb-4ej5le.unittest.google.hcpapps.net", + RecordTTL: 60, + Targets: externaldnsendpoint.Targets{ + "lrnse3.lb-4ej5le.unittest.google.hcpapps.net", + }, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "weight", + Value: "120", + }, + }, + }, + }, + }, + want: []*externaldnsendpoint.Endpoint{ + { + DNSName: "default.lb-4ej5le.unittest.google.hcpapps.net", + RecordType: "CNAME", + RecordTTL: 60, + Targets: externaldnsendpoint.Targets{ + "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + "lrnse3.lb-4ej5le.unittest.google.hcpapps.net", + }, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "weighted", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + Value: "120", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "lrnse3.lb-4ej5le.unittest.google.hcpapps.net", + Value: "120", + }, + }, + }, + }, + }, + { + name: "multiple geo targets", + args: args{ + endpoints: []*externaldnsendpoint.Endpoint{ { DNSName: "lb-4ej5le.unittest.google.hcpapps.net", RecordType: "CNAME", @@ -177,368 +397,637 @@ func Test_toResourceRecordSets(t *testing.T) { "europe-west1.lb-4ej5le.unittest.google.hcpapps.net", }, RecordTTL: 300, - ProviderSpecific: v1alpha1.ProviderSpecific{ - v1alpha1.ProviderSpecificProperty{ + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ Name: "geo-code", Value: "europe-west1", }, }, }, { - DNSName: "unittest.google.hcpapps.net", - RecordType: "CNAME", - RecordTTL: 300, + DNSName: "lb-4ej5le.unittest.google.hcpapps.net", + RecordType: "CNAME", + SetIdentifier: "us-east1", Targets: []string{ - "lb-4ej5le.unittest.google.hcpapps.net", + "us-east1.lb-4ej5le.unittest.google.hcpapps.net", + }, + RecordTTL: 300, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "geo-code", + Value: "us-east1", + }, }, - SetIdentifier: "", }, }, }, - want: []*dnsv1.ResourceRecordSet{ + want: []*externaldnsendpoint.Endpoint{ { - Name: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net.", - Rrdatas: []string{ - "0.0.0.0", + DNSName: "lb-4ej5le.unittest.google.hcpapps.net", + RecordType: "CNAME", + RecordTTL: 300, + Targets: externaldnsendpoint.Targets{ + "europe-west1.lb-4ej5le.unittest.google.hcpapps.net", + "us-east1.lb-4ej5le.unittest.google.hcpapps.net", }, - Ttl: 60, - Type: "A", - }, - { - Name: "europe-west1.lb-4ej5le.unittest.google.hcpapps.net.", - RoutingPolicy: &dnsv1.RRSetRoutingPolicy{ - Wrr: &dnsv1.RRSetRoutingPolicyWrrPolicy{ - Items: []*dnsv1.RRSetRoutingPolicyWrrPolicyWrrPolicyItem{ - { - Rrdatas: []string{ - "2c71gf.lb-4ej5le.unittest.google.hcpapps.net.", - }, - Weight: 60, - }, - }, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "geo", }, - }, - Ttl: 60, - Type: "CNAME", - }, - - { - Name: "lb-4ej5le.unittest.google.hcpapps.net.", - RoutingPolicy: &dnsv1.RRSetRoutingPolicy{ - Geo: &dnsv1.RRSetRoutingPolicyGeoPolicy{ - EnableFencing: false, - Items: []*dnsv1.RRSetRoutingPolicyGeoPolicyGeoPolicyItem{ - { - Location: "europe-west1", - Rrdatas: []string{ - "europe-west1.lb-4ej5le.unittest.google.hcpapps.net.", - }, - }, - }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "europe-west1.lb-4ej5le.unittest.google.hcpapps.net", + Value: "europe-west1", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "us-east1.lb-4ej5le.unittest.google.hcpapps.net", + Value: "us-east1", }, }, - Ttl: 300, - Type: "CNAME", - }, - - { - Name: "unittest.google.hcpapps.net.", - Rrdatas: []string{ - "lb-4ej5le.unittest.google.hcpapps.net.", - }, - Ttl: 300, - Type: "CNAME", }, }, }, { - name: "Successful test no Geo & weight", + name: "multiple geo and weighted targets", args: args{ - allEndpoints: []*v1alpha1.Endpoint{ + endpoints: []*externaldnsendpoint.Endpoint{ { - DNSName: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + DNSName: "cluster1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", RecordType: "A", - RecordTTL: 60, - Targets: v1alpha1.Targets{ - "0.0.0.0", + Targets: []string{ + "172.18.200.1", }, - SetIdentifier: "", + RecordTTL: 60, }, { - DNSName: "default.lb-4ej5le.unittest.google.hcpapps.net", - RecordType: "CNAME", - SetIdentifier: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + DNSName: "cluster2.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "A", + Targets: []string{ + "172.18.200.2", + }, + RecordTTL: 60, + }, + { + DNSName: "cluster3.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "A", + Targets: []string{ + "172.18.200.3", + }, + RecordTTL: 60, + }, + { + DNSName: "loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 300, + }, + { + DNSName: "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "cluster1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, RecordTTL: 60, - Targets: v1alpha1.Targets{ - "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + SetIdentifier: "cluster1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "weight", + Value: "200", + }, + }, + }, + { + DNSName: "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "cluster2.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", }, - ProviderSpecific: v1alpha1.ProviderSpecific{ - v1alpha1.ProviderSpecificProperty{ + RecordTTL: 60, + SetIdentifier: "cluster2.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ Name: "weight", - Value: "120", + Value: "100", }, }, }, { - DNSName: "lb-4ej5le.unittest.google.hcpapps.net", - RecordType: "CNAME", - SetIdentifier: "default", + DNSName: "us-east1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", Targets: []string{ - "default.lb-4ej5le.unittest.google.hcpapps.net", + "cluster3.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", }, - RecordTTL: 300, - ProviderSpecific: v1alpha1.ProviderSpecific{ - v1alpha1.ProviderSpecificProperty{ + RecordTTL: 60, + SetIdentifier: "cluster3.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "weight", + Value: "100", + }, + }, + }, + { + DNSName: "lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 300, + SetIdentifier: "europe-west1", + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ Name: "geo-code", - Value: "*", + Value: "europe-west1", + }, + }, + }, + { + DNSName: "lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "us-east1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 300, + SetIdentifier: "us-east1", + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "geo-code", + Value: "us-east1", }, }, }, { - DNSName: "unittest.google.hcpapps.net", + DNSName: "lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", RecordType: "CNAME", - RecordTTL: 300, Targets: []string{ - "lb-4ej5le.unittest.google.hcpapps.net", + "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 300, + SetIdentifier: "default", + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "geo-code", + Value: "*", + }, }, - SetIdentifier: "", }, }, }, - want: []*dnsv1.ResourceRecordSet{ + want: []*externaldnsendpoint.Endpoint{ { - Name: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net.", - Rrdatas: []string{ - "0.0.0.0", + DNSName: "cluster1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "A", + Targets: []string{ + "172.18.200.1", }, - Ttl: 60, - Type: "A", + RecordTTL: 60, }, { - Name: "default.lb-4ej5le.unittest.google.hcpapps.net.", - RoutingPolicy: &dnsv1.RRSetRoutingPolicy{ - Wrr: &dnsv1.RRSetRoutingPolicyWrrPolicy{ - Items: []*dnsv1.RRSetRoutingPolicyWrrPolicyWrrPolicyItem{ - { - Rrdatas: []string{ - "2c71gf.lb-4ej5le.unittest.google.hcpapps.net.", - }, - Weight: 120, - }, - }, + DNSName: "cluster2.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "A", + Targets: []string{ + "172.18.200.2", + }, + RecordTTL: 60, + }, + { + DNSName: "cluster3.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "A", + Targets: []string{ + "172.18.200.3", + }, + RecordTTL: 60, + }, + { + DNSName: "loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 300, + }, + { + DNSName: "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "cluster1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + "cluster2.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 60, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "weighted", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "cluster1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "200", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "cluster2.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "100", }, }, - Ttl: 60, - Type: "CNAME", }, { - Name: "lb-4ej5le.unittest.google.hcpapps.net.", - RoutingPolicy: &dnsv1.RRSetRoutingPolicy{ - Geo: &dnsv1.RRSetRoutingPolicyGeoPolicy{ - EnableFencing: false, - Items: []*dnsv1.RRSetRoutingPolicyGeoPolicyGeoPolicyItem{ - { - Location: "europe-west1", - Rrdatas: []string{ - "default.lb-4ej5le.unittest.google.hcpapps.net.", - }, - }, - }, + DNSName: "us-east1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "cluster3.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 60, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "weighted", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "cluster3.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "100", }, }, - Ttl: 300, - Type: "CNAME", }, { - Name: "unittest.google.hcpapps.net.", - Rrdatas: []string{ - "lb-4ej5le.unittest.google.hcpapps.net.", + DNSName: "lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + "us-east1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 300, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "geo", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "europe-west1", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "us-east1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "us-east1", + }, }, - Ttl: 300, - Type: "CNAME", }, }, }, { - name: "Successful test weight round robin with multiple targets", + name: "multiple geo and weighted targets already in google format", args: args{ - allEndpoints: []*v1alpha1.Endpoint{ + endpoints: []*externaldnsendpoint.Endpoint{ { - DNSName: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + DNSName: "cluster1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", RecordType: "A", - RecordTTL: 60, - Targets: v1alpha1.Targets{ - "0.0.0.0", + Targets: []string{ + "172.18.200.1", }, - SetIdentifier: "", + RecordTTL: 60, }, { - DNSName: "lrnse3.lb-4ej5le.unittest.google.hcpapps.net", + DNSName: "cluster2.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", RecordType: "A", - RecordTTL: 60, - Targets: v1alpha1.Targets{ - "0.0.0.1", + Targets: []string{ + "172.18.200.2", }, - SetIdentifier: "", + RecordTTL: 60, }, { - DNSName: "default.lb-4ej5le.unittest.google.hcpapps.net", - RecordType: "CNAME", - SetIdentifier: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", - RecordTTL: 60, - Targets: v1alpha1.Targets{ - "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + DNSName: "cluster3.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "A", + Targets: []string{ + "172.18.200.3", }, - ProviderSpecific: v1alpha1.ProviderSpecific{ - v1alpha1.ProviderSpecificProperty{ - Name: "weight", - Value: "120", - }, + RecordTTL: 60, + }, + { + DNSName: "loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", }, + RecordTTL: 300, }, { - DNSName: "default.lb-4ej5le.unittest.google.hcpapps.net", - RecordType: "CNAME", - SetIdentifier: "lrnse3.lb-4ej5le.unittest.google.hcpapps.net", - RecordTTL: 60, - Targets: v1alpha1.Targets{ - "lrnse3.lb-4ej5le.unittest.google.hcpapps.net", + DNSName: "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "cluster1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + "cluster2.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", }, - ProviderSpecific: v1alpha1.ProviderSpecific{ - v1alpha1.ProviderSpecificProperty{ - Name: "weight", - Value: "120", + RecordTTL: 60, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "weighted", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "cluster1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "200", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "cluster2.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "100", }, }, }, { - DNSName: "lb-4ej5le.unittest.google.hcpapps.net", - RecordType: "CNAME", - SetIdentifier: "default", + DNSName: "us-east1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", Targets: []string{ - "default.lb-4ej5le.unittest.google.hcpapps.net", + "cluster3.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", }, - RecordTTL: 300, - ProviderSpecific: v1alpha1.ProviderSpecific{ - v1alpha1.ProviderSpecificProperty{ - Name: "geo-code", - Value: "*", + RecordTTL: 60, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "weighted", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "cluster3.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "100", }, }, }, { - DNSName: "unittest.google.hcpapps.net", + DNSName: "lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", RecordType: "CNAME", - RecordTTL: 300, Targets: []string{ - "lb-4ej5le.unittest.google.hcpapps.net", + "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + "us-east1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 300, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "geo", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "europe-west1", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "us-east1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "us-east1", + }, }, - SetIdentifier: "", }, }, }, - want: []*dnsv1.ResourceRecordSet{ + want: []*externaldnsendpoint.Endpoint{ { - Name: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net.", - Rrdatas: []string{ - "0.0.0.0", + DNSName: "cluster1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "A", + Targets: []string{ + "172.18.200.1", }, - Ttl: 60, - Type: "A", + RecordTTL: 60, }, { - Name: "lrnse3.lb-4ej5le.unittest.google.hcpapps.net.", - Rrdatas: []string{ - "0.0.0.1", + DNSName: "cluster2.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "A", + Targets: []string{ + "172.18.200.2", }, - Ttl: 60, - Type: "A", + RecordTTL: 60, }, { - Name: "default.lb-4ej5le.unittest.google.hcpapps.net.", - RoutingPolicy: &dnsv1.RRSetRoutingPolicy{ - Wrr: &dnsv1.RRSetRoutingPolicyWrrPolicy{ - Items: []*dnsv1.RRSetRoutingPolicyWrrPolicyWrrPolicyItem{ - { - Rrdatas: []string{ - "2c71gf.lb-4ej5le.unittest.google.hcpapps.net.", - }, - Weight: 120, - }, - { - Rrdatas: []string{ - "lrnse3.lb-4ej5le.unittest.google.hcpapps.net.", - }, - Weight: 120, - }, - }, + DNSName: "cluster3.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "A", + Targets: []string{ + "172.18.200.3", + }, + RecordTTL: 60, + }, + { + DNSName: "loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 300, + }, + { + DNSName: "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "cluster1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + "cluster2.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 60, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "weighted", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "cluster1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "200", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "cluster2.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "100", }, }, - Ttl: 60, - Type: "CNAME", }, { - Name: "lb-4ej5le.unittest.google.hcpapps.net.", - RoutingPolicy: &dnsv1.RRSetRoutingPolicy{ - Geo: &dnsv1.RRSetRoutingPolicyGeoPolicy{ - EnableFencing: false, - Items: []*dnsv1.RRSetRoutingPolicyGeoPolicyGeoPolicyItem{ - { - Location: "europe-west1", - Rrdatas: []string{ - "default.lb-4ej5le.unittest.google.hcpapps.net.", - }, - }, - }, + DNSName: "us-east1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "cluster3.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 60, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "weighted", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "cluster3.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "100", }, }, - Ttl: 300, - Type: "CNAME", }, { - Name: "unittest.google.hcpapps.net.", - Rrdatas: []string{ - "lb-4ej5le.unittest.google.hcpapps.net.", + DNSName: "lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + RecordType: "CNAME", + Targets: []string{ + "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + "us-east1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + }, + RecordTTL: 300, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "geo", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "europe-west1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "europe-west1", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "us-east1.lb-gw1-ns1.loadbalanced.mn.google.hcpapps.net", + Value: "us-east1", + }, }, - Ttl: 300, - Type: "CNAME", }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := toResourceRecordSets(tt.args.allEndpoints) + got := endpointsToGoogleFormat(tt.args.endpoints) sorted(got) sorted(tt.want) - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("toResourceRecordSets() = %+v, want %+v", got, tt.want) + if !equality.Semantic.DeepEqual(got, tt.want) { + t.Errorf("endpointsToGoogleFormat() = %+v, want %+v", got, tt.want) } - }) } } -func sorted(rrset []*dnsv1.ResourceRecordSet) { - sort.Slice(rrset, func(i, j int) bool { - return rrset[i].Name < rrset[j].Name - }) -} - -type MockResourceRecordSetsListCall struct { - PagesFunc func(ctx context.Context, f func(*dnsv1.ResourceRecordSetsListResponse) error) error -} - -func (m *MockResourceRecordSetsListCall) Pages(ctx context.Context, f func(*dnsv1.ResourceRecordSetsListResponse) error) error { - return m.PagesFunc(ctx, f) - -} - -type MockResourceRecordSetsClient struct { - ListFunc func(project string, managedZone string) resourceRecordSetsListCallInterface -} - -func (m *MockResourceRecordSetsClient) List(project string, managedZone string) resourceRecordSetsListCallInterface { - - return m.ListFunc(project, managedZone) +func Test_resourceRecordSetFromEndpoint(t *testing.T) { + type args struct { + endpoint *externaldnsendpoint.Endpoint + } + tests := []struct { + name string + args args + want *dnsv1.ResourceRecordSet + }{ + { + name: "test A record", + args: args{ + endpoint: &externaldnsendpoint.Endpoint{ + DNSName: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + RecordType: "A", + RecordTTL: 60, + Targets: externaldnsendpoint.Targets{ + "0.0.0.0", + }, + SetIdentifier: "", + }, + }, + want: &dnsv1.ResourceRecordSet{ + Name: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net.", + Rrdatas: []string{ + "0.0.0.0", + }, + Ttl: 60, + Type: "A", + }, + }, + { + name: "test CNAME with weight and multiple targets", + args: args{ + endpoint: &externaldnsendpoint.Endpoint{ + DNSName: "default.lb-4ej5le.unittest.google.hcpapps.net", + RecordType: "CNAME", + RecordTTL: 60, + Targets: externaldnsendpoint.Targets{ + "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + "lrnse3.lb-4ej5le.unittest.google.hcpapps.net", + }, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "weighted", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "2c71gf.lb-4ej5le.unittest.google.hcpapps.net", + Value: "120", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "lrnse3.lb-4ej5le.unittest.google.hcpapps.net", + Value: "120", + }, + }, + }, + }, + want: &dnsv1.ResourceRecordSet{ + Name: "default.lb-4ej5le.unittest.google.hcpapps.net.", + RoutingPolicy: &dnsv1.RRSetRoutingPolicy{ + Wrr: &dnsv1.RRSetRoutingPolicyWrrPolicy{ + Items: []*dnsv1.RRSetRoutingPolicyWrrPolicyWrrPolicyItem{ + { + Rrdatas: []string{ + "2c71gf.lb-4ej5le.unittest.google.hcpapps.net.", + }, + Weight: 120, + }, + { + Rrdatas: []string{ + "lrnse3.lb-4ej5le.unittest.google.hcpapps.net.", + }, + Weight: 120, + }, + }, + }, + }, + Ttl: 60, + Type: "CNAME", + }, + }, + { + name: "test CNAME with geo and multiple targets", + args: args{ + endpoint: &externaldnsendpoint.Endpoint{ + DNSName: "lb-4ej5le.unittest.google.hcpapps.net", + RecordType: "CNAME", + RecordTTL: 300, + Targets: externaldnsendpoint.Targets{ + "europe-west1.lb-4ej5le.unittest.google.hcpapps.net", + "us-east1.lb-4ej5le.unittest.google.hcpapps.net", + }, + ProviderSpecific: externaldnsendpoint.ProviderSpecific{ + externaldnsendpoint.ProviderSpecificProperty{ + Name: "routingpolicy", + Value: "geo", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "europe-west1.lb-4ej5le.unittest.google.hcpapps.net", + Value: "europe-west1", + }, + externaldnsendpoint.ProviderSpecificProperty{ + Name: "us-east1.lb-4ej5le.unittest.google.hcpapps.net", + Value: "us-east1", + }, + }, + }, + }, + want: &dnsv1.ResourceRecordSet{ + Name: "lb-4ej5le.unittest.google.hcpapps.net.", + RoutingPolicy: &dnsv1.RRSetRoutingPolicy{ + Geo: &dnsv1.RRSetRoutingPolicyGeoPolicy{ + EnableFencing: false, + Items: []*dnsv1.RRSetRoutingPolicyGeoPolicyGeoPolicyItem{ + { + Location: "europe-west1", + Rrdatas: []string{ + "europe-west1.lb-4ej5le.unittest.google.hcpapps.net.", + }, + }, + { + Location: "us-east1", + Rrdatas: []string{ + "us-east1.lb-4ej5le.unittest.google.hcpapps.net.", + }, + }, + }, + }, + }, + Ttl: 300, + Type: "CNAME", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := resourceRecordSetFromEndpoint(tt.args.endpoint); !equality.Semantic.DeepEqual(got, tt.want) { + t.Errorf("resourceRecordSetFromEndpoint() = %+v, want %+v", got, tt.want) + } + }) + } } diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 5b78f952..e6a4a452 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -4,17 +4,15 @@ import ( "errors" "regexp" + externaldnsendpoint "sigs.k8s.io/external-dns/endpoint" + externaldnsprovider "sigs.k8s.io/external-dns/provider" + "github.com/kuadrant/dns-operator/api/v1alpha1" ) // Provider knows how to manage DNS zones only as pertains to routing. type Provider interface { - - // Ensure will create or update record. - Ensure(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error - - // Delete will delete record. - Delete(record *v1alpha1.DNSRecord, managedZone *v1alpha1.ManagedZone) error + externaldnsprovider.Provider // Ensure will create or update a managed zone, returns an array of NameServers for that zone. EnsureManagedZone(managedZone *v1alpha1.ManagedZone) (ManagedZoneOutput, error) @@ -23,6 +21,15 @@ type Provider interface { DeleteManagedZone(managedZone *v1alpha1.ManagedZone) error } +type Config struct { + // only consider hosted zones managing domains ending in this suffix + DomainFilter externaldnsendpoint.DomainFilter + // filter for zones based on visibility + ZoneTypeFilter externaldnsprovider.ZoneTypeFilter + // only consider hosted zones ending with this zone id + ZoneIDFilter externaldnsprovider.ZoneIDFilter +} + type ProviderSpecificLabels struct { Weight string HealthCheckID string