feat(kubernetes): add provider.kubernetes.delimiter config property

the delimiter configuration property for kubernetes allows you to change the default "_" delimiter.

By specifying "/" or "." as a delimiter you ensure that you won't collide with objects names that contains the default delimiter "_".

Fixes #207
This commit is contained in:
Alexis Couvreur
2024-02-05 16:23:45 +00:00
parent 99478819f8
commit 60b270472d
13 changed files with 126 additions and 33 deletions

View File

@@ -5,7 +5,7 @@
"ghcr.io/devcontainers/features/node:1": { "ghcr.io/devcontainers/features/node:1": {
"version": "lts" "version": "lts"
}, },
"ghcr.io/devcontainers/features/docker-in-docker:1": {}, "ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/git:1": {}, "ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/go:1": {} "ghcr.io/devcontainers/features/go:1": {}
}, },

View File

@@ -22,9 +22,6 @@ import (
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
) )
// Delimiter is used to split name into kind,namespace,name,replicacount
const Delimiter = "_"
type Config struct { type Config struct {
OriginalName string OriginalName string
Kind string // deployment or statefulset Kind string // deployment or statefulset
@@ -38,11 +35,10 @@ type Workload interface {
UpdateScale(ctx context.Context, workloadName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (*autoscalingv1.Scale, error) UpdateScale(ctx context.Context, workloadName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (*autoscalingv1.Scale, error)
} }
func convertName(name string) (*Config, error) { func (provider *KubernetesProvider) convertName(name string) (*Config, error) {
// name format kind_namespace_name_replicas s := strings.Split(name, provider.delimiter)
s := strings.Split(name, Delimiter)
if len(s) < 4 { if len(s) < 4 {
return nil, errors.New("invalid name should be: kind" + Delimiter + "namespace" + Delimiter + "name" + Delimiter + "replicas") return nil, errors.New("invalid name should be: kind" + provider.delimiter + "namespace" + provider.delimiter + "name" + provider.delimiter + "replicas")
} }
replicas, err := strconv.Atoi(s[3]) replicas, err := strconv.Atoi(s[3])
if err != nil { if err != nil {
@@ -58,8 +54,18 @@ func convertName(name string) (*Config, error) {
}, nil }, nil
} }
func (provider *KubernetesProvider) convertStatefulset(ss *appsv1.StatefulSet, replicas int32) string {
return fmt.Sprintf("statefulset%s%s%s%s%s%d", provider.delimiter, ss.Namespace, provider.delimiter, ss.Name, provider.delimiter, replicas)
}
func (provider *KubernetesProvider) convertDeployment(d *appsv1.Deployment, replicas int32) string {
return fmt.Sprintf("statefulset%s%s%s%s%s%d", provider.delimiter, d.Namespace, provider.delimiter, d.Name, provider.delimiter, replicas)
}
type KubernetesProvider struct { type KubernetesProvider struct {
Client kubernetes.Interface Client kubernetes.Interface
delimiter string
} }
func NewKubernetesProvider(providerConfig providerConfig.Kubernetes) (*KubernetesProvider, error) { func NewKubernetesProvider(providerConfig providerConfig.Kubernetes) (*KubernetesProvider, error) {
@@ -79,13 +85,14 @@ func NewKubernetesProvider(providerConfig providerConfig.Kubernetes) (*Kubernete
} }
return &KubernetesProvider{ return &KubernetesProvider{
Client: client, Client: client,
delimiter: providerConfig.Delimiter,
}, nil }, nil
} }
func (provider *KubernetesProvider) Start(ctx context.Context, name string) (instance.State, error) { func (provider *KubernetesProvider) Start(ctx context.Context, name string) (instance.State, error) {
config, err := convertName(name) config, err := provider.convertName(name)
if err != nil { if err != nil {
return instance.UnrecoverableInstanceState(name, err.Error(), int(config.Replicas)) return instance.UnrecoverableInstanceState(name, err.Error(), int(config.Replicas))
} }
@@ -94,7 +101,7 @@ func (provider *KubernetesProvider) Start(ctx context.Context, name string) (ins
} }
func (provider *KubernetesProvider) Stop(ctx context.Context, name string) (instance.State, error) { func (provider *KubernetesProvider) Stop(ctx context.Context, name string) (instance.State, error) {
config, err := convertName(name) config, err := provider.convertName(name)
if err != nil { if err != nil {
return instance.UnrecoverableInstanceState(name, err.Error(), int(config.Replicas)) return instance.UnrecoverableInstanceState(name, err.Error(), int(config.Replicas))
} }
@@ -121,12 +128,11 @@ func (provider *KubernetesProvider) GetGroups(ctx context.Context) (map[string][
group := groups[groupName] group := groups[groupName]
// TOOD: Use annotation for scale // TOOD: Use annotation for scale
name := fmt.Sprintf("%s_%s_%s_%d", "deployment", deployment.Namespace, deployment.Name, 1) name := provider.convertDeployment(&deployment, 1)
group = append(group, name) group = append(group, name)
groups[groupName] = group groups[groupName] = group
} }
statefulSets, err := provider.Client.AppsV1().StatefulSets(core_v1.NamespaceAll).List(ctx, metav1.ListOptions{ statefulSets, err := provider.Client.AppsV1().StatefulSets(core_v1.NamespaceAll).List(ctx, metav1.ListOptions{
LabelSelector: enableLabel, LabelSelector: enableLabel,
}) })
@@ -143,7 +149,7 @@ func (provider *KubernetesProvider) GetGroups(ctx context.Context) (map[string][
group := groups[groupName] group := groups[groupName]
// TOOD: Use annotation for scale // TOOD: Use annotation for scale
name := fmt.Sprintf("%s_%s_%s_%d", "statefulset", statefulSet.Namespace, statefulSet.Name, 1) name := provider.convertStatefulset(&statefulSet, 1)
group = append(group, name) group = append(group, name)
groups[groupName] = group groups[groupName] = group
} }
@@ -179,7 +185,7 @@ func (provider *KubernetesProvider) scale(ctx context.Context, config *Config, r
} }
func (provider *KubernetesProvider) GetState(ctx context.Context, name string) (instance.State, error) { func (provider *KubernetesProvider) GetState(ctx context.Context, name string) (instance.State, error) {
config, err := convertName(name) config, err := provider.convertName(name)
if err != nil { if err != nil {
return instance.UnrecoverableInstanceState(name, err.Error(), int(config.Replicas)) return instance.UnrecoverableInstanceState(name, err.Error(), int(config.Replicas))
} }
@@ -243,12 +249,12 @@ func (provider *KubernetesProvider) watchDeployents(instance chan<- string) cach
} }
if *newDeployment.Spec.Replicas == 0 { if *newDeployment.Spec.Replicas == 0 {
instance <- fmt.Sprintf("deployment_%s_%s_%d", newDeployment.Namespace, newDeployment.Name, *oldDeployment.Spec.Replicas) instance <- provider.convertDeployment(newDeployment, *oldDeployment.Spec.Replicas)
} }
}, },
DeleteFunc: func(obj interface{}) { DeleteFunc: func(obj interface{}) {
deletedDeployment := obj.(*appsv1.Deployment) deletedDeployment := obj.(*appsv1.Deployment)
instance <- fmt.Sprintf("deployment_%s_%s_%d", deletedDeployment.Namespace, deletedDeployment.Name, *deletedDeployment.Spec.Replicas) instance <- provider.convertDeployment(deletedDeployment, *deletedDeployment.Spec.Replicas)
}, },
} }
factory := informers.NewSharedInformerFactoryWithOptions(provider.Client, 2*time.Second, informers.WithNamespace(core_v1.NamespaceAll)) factory := informers.NewSharedInformerFactoryWithOptions(provider.Client, 2*time.Second, informers.WithNamespace(core_v1.NamespaceAll))
@@ -269,12 +275,12 @@ func (provider *KubernetesProvider) watchStatefulSets(instance chan<- string) ca
} }
if *newStatefulSet.Spec.Replicas == 0 { if *newStatefulSet.Spec.Replicas == 0 {
instance <- fmt.Sprintf("statefulset_%s_%s_%d", newStatefulSet.Namespace, newStatefulSet.Name, *oldStatefulSet.Spec.Replicas) instance <- provider.convertStatefulset(newStatefulSet, *oldStatefulSet.Spec.Replicas)
} }
}, },
DeleteFunc: func(obj interface{}) { DeleteFunc: func(obj interface{}) {
deletedStatefulSet := obj.(*appsv1.StatefulSet) deletedStatefulSet := obj.(*appsv1.StatefulSet)
instance <- fmt.Sprintf("statefulset__%s_%s_%d", deletedStatefulSet.Namespace, deletedStatefulSet.Name, *deletedStatefulSet.Spec.Replicas) instance <- provider.convertStatefulset(deletedStatefulSet, *deletedStatefulSet.Spec.Replicas)
}, },
} }
factory := informers.NewSharedInformerFactoryWithOptions(provider.Client, 2*time.Second, informers.WithNamespace(core_v1.NamespaceAll)) factory := informers.NewSharedInformerFactoryWithOptions(provider.Client, 2*time.Second, informers.WithNamespace(core_v1.NamespaceAll))

View File

@@ -90,7 +90,8 @@ func TestKubernetesProvider_Start(t *testing.T) {
deploymentAPI := mocks.DeploymentMock{} deploymentAPI := mocks.DeploymentMock{}
statefulsetAPI := mocks.StatefulSetsMock{} statefulsetAPI := mocks.StatefulSetsMock{}
provider := KubernetesProvider{ provider := KubernetesProvider{
Client: mocks.NewKubernetesAPIClientMock(&deploymentAPI, &statefulsetAPI), Client: mocks.NewKubernetesAPIClientMock(&deploymentAPI, &statefulsetAPI),
delimiter: "_",
} }
deploymentAPI.On("GetScale", mock.Anything, tt.data.name, metav1.GetOptions{}).Return(tt.data.get, nil) deploymentAPI.On("GetScale", mock.Anything, tt.data.name, metav1.GetOptions{}).Return(tt.data.get, nil)
@@ -188,7 +189,8 @@ func TestKubernetesProvider_Stop(t *testing.T) {
deploymentAPI := mocks.DeploymentMock{} deploymentAPI := mocks.DeploymentMock{}
statefulsetAPI := mocks.StatefulSetsMock{} statefulsetAPI := mocks.StatefulSetsMock{}
provider := KubernetesProvider{ provider := KubernetesProvider{
Client: mocks.NewKubernetesAPIClientMock(&deploymentAPI, &statefulsetAPI), Client: mocks.NewKubernetesAPIClientMock(&deploymentAPI, &statefulsetAPI),
delimiter: "_",
} }
deploymentAPI.On("GetScale", mock.Anything, tt.data.name, metav1.GetOptions{}).Return(tt.data.get, nil) deploymentAPI.On("GetScale", mock.Anything, tt.data.name, metav1.GetOptions{}).Return(tt.data.get, nil)
@@ -316,7 +318,8 @@ func TestKubernetesProvider_GetState(t *testing.T) {
deploymentAPI := mocks.DeploymentMock{} deploymentAPI := mocks.DeploymentMock{}
statefulsetAPI := mocks.StatefulSetsMock{} statefulsetAPI := mocks.StatefulSetsMock{}
provider := KubernetesProvider{ provider := KubernetesProvider{
Client: mocks.NewKubernetesAPIClientMock(&deploymentAPI, &statefulsetAPI), Client: mocks.NewKubernetesAPIClientMock(&deploymentAPI, &statefulsetAPI),
delimiter: "_",
} }
deploymentAPI.On("Get", mock.Anything, tt.data.name, metav1.GetOptions{}).Return(tt.data.getDeployment, nil) deploymentAPI.On("Get", mock.Anything, tt.data.name, metav1.GetOptions{}).Return(tt.data.getDeployment, nil)

View File

@@ -46,10 +46,12 @@ It provides an integrations with multiple reverse proxies and different loading
// Provider flags // Provider flags
startCmd.Flags().StringVar(&conf.Provider.Name, "provider.name", "docker", fmt.Sprintf("Provider to use to manage containers %v", config.GetProviders())) startCmd.Flags().StringVar(&conf.Provider.Name, "provider.name", "docker", fmt.Sprintf("Provider to use to manage containers %v", config.GetProviders()))
viper.BindPFlag("provider.name", startCmd.Flags().Lookup("provider.name")) viper.BindPFlag("provider.name", startCmd.Flags().Lookup("provider.name"))
startCmd.Flags().Float32Var(&conf.Provider.Kubernetes.QPS, "provider.kubernetes.qps", 5, fmt.Sprintf("QPS limit for K8S API access client-side throttling")) startCmd.Flags().Float32Var(&conf.Provider.Kubernetes.QPS, "provider.kubernetes.qps", 5, "QPS limit for K8S API access client-side throttling")
viper.BindPFlag("provider.kubernetes.qps", startCmd.Flags().Lookup("provider.kubernetes.qps")) viper.BindPFlag("provider.kubernetes.qps", startCmd.Flags().Lookup("provider.kubernetes.qps"))
startCmd.Flags().IntVar(&conf.Provider.Kubernetes.Burst, "provider.kubernetes.burst", 10, fmt.Sprintf("Maximum burst for K8S API acees client-side throttling")) startCmd.Flags().IntVar(&conf.Provider.Kubernetes.Burst, "provider.kubernetes.burst", 10, "Maximum burst for K8S API acees client-side throttling")
viper.BindPFlag("provider.kubernetes.burst", startCmd.Flags().Lookup("provider.kubernetes.burst")) viper.BindPFlag("provider.kubernetes.burst", startCmd.Flags().Lookup("provider.kubernetes.burst"))
startCmd.Flags().StringVar(&conf.Provider.Kubernetes.Delimiter, "provider.kubernetes.delimiter", "_", "Delimiter used for namespace/resource type/name resolution. Defaults to \"_\" for backward compatibility. But you should use \"/\" or \".\"")
viper.BindPFlag("provider.kubernetes.delimiter", startCmd.Flags().Lookup("provider.kubernetes.delimiter"))
// Server flags // Server flags
startCmd.Flags().IntVar(&conf.Server.Port, "server.port", 10000, "The server port to use") startCmd.Flags().IntVar(&conf.Server.Port, "server.port", 10000, "The server port to use")
viper.BindPFlag("server.port", startCmd.Flags().Lookup("server.port")) viper.BindPFlag("server.port", startCmd.Flags().Lookup("server.port"))

View File

@@ -17,6 +17,32 @@ import (
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
) )
func TestDefault(t *testing.T) {
testDir, err := os.Getwd()
require.NoError(t, err, "error getting the current working directory")
wantConfig, err := ioutil.ReadFile(filepath.Join(testDir, "testdata", "config_default.json"))
require.NoError(t, err, "error reading test config file")
// CHANGE `startCmd` behavior to only print the config, this is for testing purposes only
newStartCommand = mockStartCommand
t.Run("config file", func(t *testing.T) {
conf = config.NewConfig()
cmd := NewRootCommand()
output := &bytes.Buffer{}
cmd.SetOut(output)
cmd.SetArgs([]string{
"start",
})
cmd.Execute()
gotOutput := output.String()
assert.Equal(t, string(wantConfig), gotOutput)
})
}
func TestPrecedence(t *testing.T) { func TestPrecedence(t *testing.T) {
testDir, err := os.Getwd() testDir, err := os.Getwd()
require.NoError(t, err, "error getting the current working directory") require.NoError(t, err, "error getting the current working directory")
@@ -82,6 +108,7 @@ func TestPrecedence(t *testing.T) {
"--provider.name", "cli", "--provider.name", "cli",
"--provider.kubernetes.qps", "256", "--provider.kubernetes.qps", "256",
"--provider.kubernetes.burst", "512", "--provider.kubernetes.burst", "512",
"--provider.kubernetes.delimiter", "_",
"--server.port", "3333", "--server.port", "3333",
"--server.base-path", "/cli/", "--server.base-path", "/cli/",
"--storage.file", "/tmp/cli.json", "--storage.file", "/tmp/cli.json",

View File

@@ -1,6 +1,7 @@
PROVIDER_NAME=envvar PROVIDER_NAME=envvar
PROVIDER_KUBERNETES_QPS=16 PROVIDER_KUBERNETES_QPS=16
PROVIDER_KUBERNETES_BURST=32 PROVIDER_KUBERNETES_BURST=32
PROVIDER_KUBERNETES_DELIMITER=/
SERVER_PORT=2222 SERVER_PORT=2222
SERVER_BASE_PATH=/envvar/ SERVER_BASE_PATH=/envvar/
STORAGE_FILE=/tmp/envvar.json STORAGE_FILE=/tmp/envvar.json

View File

@@ -3,6 +3,7 @@ provider:
kubernetes: kubernetes:
qps: 64 qps: 64
burst: 128 burst: 128
delimiter: .
server: server:
port: 1111 port: 1111
base-path: /configfile/ base-path: /configfile/

View File

@@ -10,7 +10,8 @@
"Name": "cli", "Name": "cli",
"Kubernetes": { "Kubernetes": {
"QPS": 256, "QPS": 256,
"Burst": 512 "Burst": 512,
"Delimiter": "_"
} }
}, },
"Sessions": { "Sessions": {

35
cmd/testdata/config_default.json vendored Normal file
View File

@@ -0,0 +1,35 @@
{
"Server": {
"Port": 10000,
"BasePath": "/"
},
"Storage": {
"File": ""
},
"Provider": {
"Name": "docker",
"Kubernetes": {
"QPS": 5,
"Burst": 10,
"Delimiter": "_"
}
},
"Sessions": {
"DefaultDuration": 300000000000,
"ExpirationInterval": 20000000000
},
"Logging": {
"Level": "info"
},
"Strategy": {
"Dynamic": {
"CustomThemesPath": "",
"ShowDetailsByDefault": true,
"DefaultTheme": "hacker-terminal",
"DefaultRefreshFrequency": 5000000000
},
"Blocking": {
"DefaultTimeout": 60000000000
}
}
}

View File

@@ -10,7 +10,8 @@
"Name": "envvar", "Name": "envvar",
"Kubernetes": { "Kubernetes": {
"QPS": 16, "QPS": 16,
"Burst": 32 "Burst": 32,
"Delimiter": "/"
} }
}, },
"Sessions": { "Sessions": {

View File

@@ -10,7 +10,8 @@
"Name": "configfile", "Name": "configfile",
"Kubernetes": { "Kubernetes": {
"QPS": 64, "QPS": 64,
"Burst": 128 "Burst": 128,
"Delimiter": "."
} }
}, },
"Sessions": { "Sessions": {

View File

@@ -4,10 +4,11 @@ import (
"fmt" "fmt"
) )
// Provider holds the provider description // Provider holds the provider configurations
// It can be either docker, swarm or kubernetes
type Provider struct { type Provider struct {
Name string `mapstructure:"NAME" yaml:"provider,omitempty"` // The provider name to use
// It can be either docker, swarm or kubernetes. Defaults to "docker"
Name string `mapstructure:"NAME" yaml:"provider,omitempty" default:"docker"`
Kubernetes Kubernetes Kubernetes Kubernetes
} }
@@ -16,16 +17,20 @@ type Kubernetes struct {
QPS float32 `mapstructure:"QPS" yaml:"QPS" default:"5"` QPS float32 `mapstructure:"QPS" yaml:"QPS" default:"5"`
//Maximum burst for client-side throttle //Maximum burst for client-side throttle
Burst int `mapstructure:"BURST" yaml:"Burst" default:"10"` Burst int `mapstructure:"BURST" yaml:"Burst" default:"10"`
//Delimiter used for namespace/resource type/name resolution. Defaults to "_" for backward compatibility. But you should use "/" or ".".
Delimiter string `mapstructure:"DELIMITER" yaml:"Delimiter" default:"_"`
} }
var providers = []string{"docker", "swarm", "kubernetes"} var providers = []string{"docker", "swarm", "kubernetes"}
func NewProviderConfig() Provider { func NewProviderConfig() Provider {
return Provider{ return Provider{
Name: "docker", Name: "docker",
Kubernetes: Kubernetes{ Kubernetes: Kubernetes{
QPS: 5, QPS: 5,
Burst: 10, Burst: 10,
Delimiter: "_", //Delimiter used for namespace/resource type/name resolution. Defaults to "_" for backward compatibility. But you should use "/" or ".".
}, },
} }
} }

View File

@@ -320,6 +320,7 @@ cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542
cloud.google.com/go/speech v1.20.1/go.mod h1:wwolycgONvfz2EDU8rKuHRW3+wc9ILPsAWoikBEWavY= cloud.google.com/go/speech v1.20.1/go.mod h1:wwolycgONvfz2EDU8rKuHRW3+wc9ILPsAWoikBEWavY=
cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI= cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI=
cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4=
cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
cloud.google.com/go/storagetransfer v1.8.0 h1:5T+PM+3ECU3EY2y9Brv0Sf3oka8pKmsCfpQ07+91G9o= cloud.google.com/go/storagetransfer v1.8.0 h1:5T+PM+3ECU3EY2y9Brv0Sf3oka8pKmsCfpQ07+91G9o=
cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw=
cloud.google.com/go/storagetransfer v1.10.3/go.mod h1:Up8LY2p6X68SZ+WToswpQbQHnJpOty/ACcMafuey8gc= cloud.google.com/go/storagetransfer v1.10.3/go.mod h1:Up8LY2p6X68SZ+WToswpQbQHnJpOty/ACcMafuey8gc=
@@ -436,6 +437,7 @@ github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec h1:EdRZT3IeKQmfCSrgo8SZ8V3MEnskuJP0wCYNpe+aiXo= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec h1:EdRZT3IeKQmfCSrgo8SZ8V3MEnskuJP0wCYNpe+aiXo=
@@ -448,6 +450,7 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 h1:58f1tJ1ra+zFINPlwLWvQsR9CzAKt2e+EWV2yX9oXQ4= github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 h1:58f1tJ1ra+zFINPlwLWvQsR9CzAKt2e+EWV2yX9oXQ4=
github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
@@ -477,8 +480,10 @@ github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.11.0 h1:jtLewhRR2vMRNnq2ZZUoCjUlgut+Y0+sDDWPOfwOi1o= github.com/envoyproxy/go-control-plane v0.11.0 h1:jtLewhRR2vMRNnq2ZZUoCjUlgut+Y0+sDDWPOfwOi1o=
github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI=
github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g=
github.com/envoyproxy/protoc-gen-validate v0.10.0 h1:oIfnZFdC0YhpNNEX+SuIqko4cqqVZeN9IGTrhZje83Y= github.com/envoyproxy/protoc-gen-validate v0.10.0 h1:oIfnZFdC0YhpNNEX+SuIqko4cqqVZeN9IGTrhZje83Y=
github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fasthttp/websocket v1.4.3-rc.6 h1:omHqsl8j+KXpmzRjF8bmzOSYJ8GnS0E3efi1wYT+niY= github.com/fasthttp/websocket v1.4.3-rc.6 h1:omHqsl8j+KXpmzRjF8bmzOSYJ8GnS0E3efi1wYT+niY=
@@ -522,11 +527,14 @@ github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/s2a-go v0.1.3 h1:FAgZmpLl/SXurPEZyCMPBIiiYeTbqfjlbdnCNTAkbGE= github.com/google/s2a-go v0.1.3 h1:FAgZmpLl/SXurPEZyCMPBIiiYeTbqfjlbdnCNTAkbGE=
github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= 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/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc=
github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
@@ -764,6 +772,7 @@ go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
@@ -799,6 +808,7 @@ google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0
google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
google.golang.org/api v0.122.0 h1:zDobeejm3E7pEG1mNHvdxvjs5XJoCMzyNH+CmwL94Es= google.golang.org/api v0.122.0 h1:zDobeejm3E7pEG1mNHvdxvjs5XJoCMzyNH+CmwL94Es=
google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms=
google.golang.org/api v0.153.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA=
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=