diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 813420d..c78665c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,7 +5,7 @@ "ghcr.io/devcontainers/features/node:1": { "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/go:1": {} }, diff --git a/app/providers/kubernetes.go b/app/providers/kubernetes.go index 0a5e2de..d669e5d 100644 --- a/app/providers/kubernetes.go +++ b/app/providers/kubernetes.go @@ -22,9 +22,6 @@ import ( "k8s.io/client-go/tools/cache" ) -// Delimiter is used to split name into kind,namespace,name,replicacount -const Delimiter = "_" - type Config struct { OriginalName string 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) } -func convertName(name string) (*Config, error) { - // name format kind_namespace_name_replicas - s := strings.Split(name, Delimiter) +func (provider *KubernetesProvider) convertName(name string) (*Config, error) { + s := strings.Split(name, provider.delimiter) 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]) if err != nil { @@ -58,8 +54,18 @@ func convertName(name string) (*Config, error) { }, 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 { - Client kubernetes.Interface + Client kubernetes.Interface + delimiter string } func NewKubernetesProvider(providerConfig providerConfig.Kubernetes) (*KubernetesProvider, error) { @@ -79,13 +85,14 @@ func NewKubernetesProvider(providerConfig providerConfig.Kubernetes) (*Kubernete } return &KubernetesProvider{ - Client: client, + Client: client, + delimiter: providerConfig.Delimiter, }, nil } func (provider *KubernetesProvider) Start(ctx context.Context, name string) (instance.State, error) { - config, err := convertName(name) + config, err := provider.convertName(name) if err != nil { 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) { - config, err := convertName(name) + config, err := provider.convertName(name) if err != nil { 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] // 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) groups[groupName] = group } - statefulSets, err := provider.Client.AppsV1().StatefulSets(core_v1.NamespaceAll).List(ctx, metav1.ListOptions{ LabelSelector: enableLabel, }) @@ -143,7 +149,7 @@ func (provider *KubernetesProvider) GetGroups(ctx context.Context) (map[string][ group := groups[groupName] // 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) 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) { - config, err := convertName(name) + config, err := provider.convertName(name) if err != nil { 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 { - 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{}) { 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)) @@ -269,12 +275,12 @@ func (provider *KubernetesProvider) watchStatefulSets(instance chan<- string) ca } 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{}) { 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)) diff --git a/app/providers/kubernetes_test.go b/app/providers/kubernetes_test.go index 63a99c9..1b571a4 100644 --- a/app/providers/kubernetes_test.go +++ b/app/providers/kubernetes_test.go @@ -90,7 +90,8 @@ func TestKubernetesProvider_Start(t *testing.T) { deploymentAPI := mocks.DeploymentMock{} statefulsetAPI := mocks.StatefulSetsMock{} 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) @@ -188,7 +189,8 @@ func TestKubernetesProvider_Stop(t *testing.T) { deploymentAPI := mocks.DeploymentMock{} statefulsetAPI := mocks.StatefulSetsMock{} 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) @@ -316,7 +318,8 @@ func TestKubernetesProvider_GetState(t *testing.T) { deploymentAPI := mocks.DeploymentMock{} statefulsetAPI := mocks.StatefulSetsMock{} 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) diff --git a/cmd/root.go b/cmd/root.go index 576b75b..986423b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -46,10 +46,12 @@ It provides an integrations with multiple reverse proxies and different loading // Provider flags 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")) - 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")) - 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")) + 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 startCmd.Flags().IntVar(&conf.Server.Port, "server.port", 10000, "The server port to use") viper.BindPFlag("server.port", startCmd.Flags().Lookup("server.port")) diff --git a/cmd/root_test.go b/cmd/root_test.go index 5b22fe7..f918176 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -17,6 +17,32 @@ import ( "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) { testDir, err := os.Getwd() require.NoError(t, err, "error getting the current working directory") @@ -82,6 +108,7 @@ func TestPrecedence(t *testing.T) { "--provider.name", "cli", "--provider.kubernetes.qps", "256", "--provider.kubernetes.burst", "512", + "--provider.kubernetes.delimiter", "_", "--server.port", "3333", "--server.base-path", "/cli/", "--storage.file", "/tmp/cli.json", diff --git a/cmd/testdata/config.env b/cmd/testdata/config.env index be4bd08..11fef97 100644 --- a/cmd/testdata/config.env +++ b/cmd/testdata/config.env @@ -1,6 +1,7 @@ PROVIDER_NAME=envvar PROVIDER_KUBERNETES_QPS=16 PROVIDER_KUBERNETES_BURST=32 +PROVIDER_KUBERNETES_DELIMITER=/ SERVER_PORT=2222 SERVER_BASE_PATH=/envvar/ STORAGE_FILE=/tmp/envvar.json diff --git a/cmd/testdata/config.yml b/cmd/testdata/config.yml index a23bdfc..e52299e 100644 --- a/cmd/testdata/config.yml +++ b/cmd/testdata/config.yml @@ -3,6 +3,7 @@ provider: kubernetes: qps: 64 burst: 128 + delimiter: . server: port: 1111 base-path: /configfile/ diff --git a/cmd/testdata/config_cli_wanted.json b/cmd/testdata/config_cli_wanted.json index cea8b24..2829f8e 100644 --- a/cmd/testdata/config_cli_wanted.json +++ b/cmd/testdata/config_cli_wanted.json @@ -10,7 +10,8 @@ "Name": "cli", "Kubernetes": { "QPS": 256, - "Burst": 512 + "Burst": 512, + "Delimiter": "_" } }, "Sessions": { diff --git a/cmd/testdata/config_default.json b/cmd/testdata/config_default.json new file mode 100644 index 0000000..4bf83ad --- /dev/null +++ b/cmd/testdata/config_default.json @@ -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 + } + } +} diff --git a/cmd/testdata/config_env_wanted.json b/cmd/testdata/config_env_wanted.json index 3b5afa7..ef6ca0f 100644 --- a/cmd/testdata/config_env_wanted.json +++ b/cmd/testdata/config_env_wanted.json @@ -10,7 +10,8 @@ "Name": "envvar", "Kubernetes": { "QPS": 16, - "Burst": 32 + "Burst": 32, + "Delimiter": "/" } }, "Sessions": { diff --git a/cmd/testdata/config_yaml_wanted.json b/cmd/testdata/config_yaml_wanted.json index bfa9eeb..8262d4c 100644 --- a/cmd/testdata/config_yaml_wanted.json +++ b/cmd/testdata/config_yaml_wanted.json @@ -10,7 +10,8 @@ "Name": "configfile", "Kubernetes": { "QPS": 64, - "Burst": 128 + "Burst": 128, + "Delimiter": "." } }, "Sessions": { diff --git a/config/provider.go b/config/provider.go index 9d4e4fa..064401f 100644 --- a/config/provider.go +++ b/config/provider.go @@ -4,10 +4,11 @@ import ( "fmt" ) -// Provider holds the provider description -// It can be either docker, swarm or kubernetes +// Provider holds the provider configurations 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 } @@ -16,16 +17,20 @@ type Kubernetes struct { QPS float32 `mapstructure:"QPS" yaml:"QPS" default:"5"` //Maximum burst for client-side throttle 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"} func NewProviderConfig() Provider { return Provider{ + Name: "docker", Kubernetes: Kubernetes{ - QPS: 5, - Burst: 10, + QPS: 5, + Burst: 10, + Delimiter: "_", //Delimiter used for namespace/resource type/name resolution. Defaults to "_" for backward compatibility. But you should use "/" or ".". }, } } diff --git a/go.work.sum b/go.work.sum index 25108bb..b2fc777 100644 --- a/go.work.sum +++ b/go.work.sum @@ -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/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.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/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= 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/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= 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/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= 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-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-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 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/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.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.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/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/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 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/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.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/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.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.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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= 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.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= 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/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= 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.122.0 h1:zDobeejm3E7pEG1mNHvdxvjs5XJoCMzyNH+CmwL94Es= 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-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=