From e995349ea0756c700d188b8f04e9459121219f0c Mon Sep 17 00:00:00 2001 From: Binh Tran Date: Thu, 29 Jan 2026 17:47:49 -0500 Subject: [PATCH] feat(prebuiltconfigs/alloydb-omni): Implement Alloydb omni dataplane tools (#2340) ## Description Implement Dataplane tools for alloydb omni using Postgres source and postgres tools. I also add more omni-specific tool (columnar engine). --------- Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> --- .ci/integration.cloudbuild.yaml | 23 +- cmd/root_test.go | 19 +- docs/en/reference/prebuilt-tools.md | 61 +++- go.mod | 38 +++ go.sum | 57 +++- .../prebuiltconfigs/prebuiltconfigs_test.go | 73 +++-- .../prebuiltconfigs/tools/alloydb-omni.yaml | 277 ++++++++++++++++++ .../alloydb_omni_integration_test.go | 157 ++++++++++ 8 files changed, 657 insertions(+), 48 deletions(-) create mode 100644 internal/prebuiltconfigs/tools/alloydb-omni.yaml create mode 100644 tests/alloydbomni/alloydb_omni_integration_test.go diff --git a/.ci/integration.cloudbuild.yaml b/.ci/integration.cloudbuild.yaml index 8e189f6b91..bfa16e7156 100644 --- a/.ci/integration.cloudbuild.yaml +++ b/.ci/integration.cloudbuild.yaml @@ -171,6 +171,23 @@ steps: alloydbainl \ alloydbainl + - id: "alloydb-omni" + name: golang:1 + waitFor: ["compile-test-binary"] + entrypoint: /bin/bash + env: + - "GOPATH=/gopath" + volumes: + - name: "go" + path: "/gopath" + args: + - -c + - | + .ci/test_with_coverage.sh \ + "AlloyDB Omni" \ + alloydbomni \ + postgres + - id: "bigtable" name: golang:1 waitFor: ["compile-test-binary"] @@ -676,7 +693,7 @@ steps: "Looker" \ looker \ looker - + - id: "mindsdb" name: golang:1 waitFor: ["compile-test-binary"] @@ -864,7 +881,7 @@ steps: "Snowflake" \ snowflake \ snowflake - + - id: "cassandra" name: golang:1 waitFor: ["compile-test-binary"] @@ -909,7 +926,7 @@ steps: go test -v ./tests/oracle/... \ -coverprofile=oracle_coverage.out \ -coverpkg=./internal/sources/oracle/...,./internal/tools/oracle/... - + # Coverage check total_coverage=$(go tool cover -func=oracle_coverage.out | grep "total:" | awk '{print $3}') echo "Oracle total coverage: $total_coverage" diff --git a/cmd/root_test.go b/cmd/root_test.go index c69399a800..3c55e83d93 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -1624,7 +1624,7 @@ func TestEnvVarReplacement(t *testing.T) { ${toolset_name}: - example_tool - + prompts: ${prompt_name}: description: A test prompt for {{.name}}. @@ -2054,6 +2054,7 @@ func TestSingleEdit(t *testing.T) { func TestPrebuiltTools(t *testing.T) { // Get prebuilt configs + alloydb_omni_config, _ := prebuiltconfigs.Get("alloydb-omni") alloydb_admin_config, _ := prebuiltconfigs.Get("alloydb-postgres-admin") alloydb_config, _ := prebuiltconfigs.Get("alloydb-postgres") bigquery_config, _ := prebuiltconfigs.Get("bigquery") @@ -2104,6 +2105,12 @@ func TestPrebuiltTools(t *testing.T) { t.Setenv("ALLOYDB_POSTGRES_USER", "your_alloydb_user") t.Setenv("ALLOYDB_POSTGRES_PASSWORD", "your_alloydb_password") + t.Setenv("ALLOYDB_OMNI_HOST", "localhost") + t.Setenv("ALLOYDB_OMNI_PORT", "5432") + t.Setenv("ALLOYDB_OMNI_DATABASE", "your_alloydb_db") + t.Setenv("ALLOYDB_OMNI_USER", "your_alloydb_user") + t.Setenv("ALLOYDB_OMNI_PASSWORD", "your_alloydb_password") + t.Setenv("CLICKHOUSE_PROTOCOL", "your_clickhouse_protocol") t.Setenv("CLICKHOUSE_DATABASE", "your_clickhouse_database") t.Setenv("CLICKHOUSE_PASSWORD", "your_clickhouse_password") @@ -2197,6 +2204,16 @@ func TestPrebuiltTools(t *testing.T) { in []byte wantToolset server.ToolsetConfigs }{ + { + name: "alloydb omni prebuilt tools", + in: alloydb_omni_config, + wantToolset: server.ToolsetConfigs{ + "alloydb_omni_database_tools": tools.ToolsetConfig{ + Name: "alloydb_omni_database_tools", + ToolNames: []string{"execute_sql", "list_tables", "list_active_queries", "list_available_extensions", "list_installed_extensions", "list_autovacuum_configurations", "list_columnar_configurations", "list_columnar_recommended_columns", "list_memory_configurations", "list_top_bloated_tables", "list_replication_slots", "list_invalid_indexes", "get_query_plan", "list_views", "list_schemas", "database_overview", "list_triggers", "list_indexes", "list_sequences", "long_running_transactions", "list_locks", "replication_stats", "list_query_stats", "get_column_cardinality", "list_publication_tables", "list_tablespaces", "list_pg_settings", "list_database_stats", "list_roles", "list_table_stats", "list_stored_procedure"}, + }, + }, + }, { name: "alloydb postgres admin prebuilt tools", in: alloydb_admin_config, diff --git a/docs/en/reference/prebuilt-tools.md b/docs/en/reference/prebuilt-tools.md index a539af9fb2..bf7013f902 100644 --- a/docs/en/reference/prebuilt-tools.md +++ b/docs/en/reference/prebuilt-tools.md @@ -54,9 +54,9 @@ See [Usage Examples](../reference/cli.md#examples). * `get_query_plan`: Generate the execution plan of a statement. * `list_views`: Lists views in the database from pg_views with a default limit of 50 rows. Returns schemaname, viewname and the ownername. - * `list_schemas`: Lists schemas in the database. - * `database_overview`: Fetches the current state of the PostgreSQL server. - * `list_triggers`: Lists triggers in the database. + * `list_schemas`: Lists schemas in the database. + * `database_overview`: Fetches the current state of the PostgreSQL server. + * `list_triggers`: Lists triggers in the database. * `list_indexes`: List available user indexes in a PostgreSQL database. * `list_sequences`: List sequences in a PostgreSQL database. * `list_publication_tables`: List publication tables in a PostgreSQL database. @@ -64,7 +64,7 @@ See [Usage Examples](../reference/cli.md#examples). * `list_pg_settings`: List configuration parameters for the PostgreSQL server. * `list_database_stats`: Lists the key performance and activity statistics for each database in the AlloyDB instance. - * `list_roles`: Lists all the user-created roles in PostgreSQL database. + * `list_roles`: Lists all the user-created roles in PostgreSQL database. ## AlloyDB Postgres Admin @@ -100,6 +100,43 @@ See [Usage Examples](../reference/cli.md#examples). (timeseries metrics) for queries running in an AlloyDB instance using a PromQL query. +## AlloyDB Omni + +* `--prebuilt` value: `alloydb-omni` +* **Environment Variables:** + * `ALLOYDB_OMNI_HOST`: (Optional) The hostname or IP address (Default: localhost). + * `ALLOYDB_OMNI_PORT`: (Optional) The port number (Default: 5432). + * `ALLOYDB_OMNI_DATABASE`: The name of the database to connect to. + * `ALLOYDB_OMNI_USER`: The database username. + * `ALLOYDB_OMNI_PASSWORD`: (Optional) The password for the database user. + * `ALLOYDB_OMNI_QUERY_PARAMS`: (Optional) Connection query parameters. +* **Tools:** + * `execute_sql`: Executes a SQL query. + * `list_tables`: Lists tables in the database. + * `list_autovacuum_configurations`: Lists autovacuum configurations in the + database. + * `list_columnar_configurations`: List AlloyDB Omni columnar-related configurations. + * `list_columnar_recommended_columns`: Lists columns that AlloyDB Omni recommends adding to the columnar engine. + * `list_memory_configurations`: Lists memory-related configurations in the + database. + * `list_top_bloated_tables`: List top bloated tables in the database. + * `list_replication_slots`: Lists replication slots in the database. + * `list_invalid_indexes`: Lists invalid indexes in the database. + * `get_query_plan`: Generate the execution plan of a statement. + * `list_views`: Lists views in the database from pg_views with a default + limit of 50 rows. Returns schemaname, viewname and the ownername. + * `list_schemas`: Lists schemas in the database. + * `database_overview`: Fetches the current state of the PostgreSQL server. + * `list_triggers`: Lists triggers in the database. + * `list_indexes`: List available user indexes in a PostgreSQL database. + * `list_sequences`: List sequences in a PostgreSQL database. + * `list_publication_tables`: List publication tables in a PostgreSQL database. + * `list_tablespaces`: Lists tablespaces in the database. + * `list_pg_settings`: List configuration parameters for the PostgreSQL server. + * `list_database_stats`: Lists the key performance and activity statistics for + each database in the AlloyDB instance. + * `list_roles`: Lists all the user-created roles in PostgreSQL database. + ## BigQuery * `--prebuilt` value: `bigquery` @@ -243,9 +280,9 @@ See [Usage Examples](../reference/cli.md#examples). * `get_query_plan`: Generate the execution plan of a statement. * `list_views`: Lists views in the database from pg_views with a default limit of 50 rows. Returns schemaname, viewname and the ownername. - * `list_schemas`: Lists schemas in the database. - * `database_overview`: Fetches the current state of the PostgreSQL server. - * `list_triggers`: Lists triggers in the database. + * `list_schemas`: Lists schemas in the database. + * `database_overview`: Fetches the current state of the PostgreSQL server. + * `list_triggers`: Lists triggers in the database. * `list_indexes`: List available user indexes in a PostgreSQL database. * `list_sequences`: List sequences in a PostgreSQL database. * `list_publication_tables`: List publication tables in a PostgreSQL database. @@ -253,7 +290,7 @@ See [Usage Examples](../reference/cli.md#examples). * `list_pg_settings`: List configuration parameters for the PostgreSQL server. * `list_database_stats`: Lists the key performance and activity statistics for each database in the postgreSQL instance. - * `list_roles`: Lists all the user-created roles in PostgreSQL database. + * `list_roles`: Lists all the user-created roles in PostgreSQL database. ## Cloud SQL for PostgreSQL Observability @@ -564,9 +601,9 @@ See [Usage Examples](../reference/cli.md#examples). * `get_query_plan`: Generate the execution plan of a statement. * `list_views`: Lists views in the database from pg_views with a default limit of 50 rows. Returns schemaname, viewname and the ownername. - * `list_schemas`: Lists schemas in the database. - * `database_overview`: Fetches the current state of the PostgreSQL server. - * `list_triggers`: Lists triggers in the database. + * `list_schemas`: Lists schemas in the database. + * `database_overview`: Fetches the current state of the PostgreSQL server. + * `list_triggers`: Lists triggers in the database. * `list_indexes`: List available user indexes in a PostgreSQL database. * `list_sequences`: List sequences in a PostgreSQL database. * `list_publication_tables`: List publication tables in a PostgreSQL database. @@ -574,7 +611,7 @@ See [Usage Examples](../reference/cli.md#examples). * `list_pg_settings`: List configuration parameters for the PostgreSQL server. * `list_database_stats`: Lists the key performance and activity statistics for each database in the PostgreSQL server. - * `list_roles`: Lists all the user-created roles in PostgreSQL database. + * `list_roles`: Lists all the user-created roles in PostgreSQL database. ## Google Cloud Serverless for Apache Spark diff --git a/go.mod b/go.mod index f592eb67d2..0afb95674a 100644 --- a/go.mod +++ b/go.mod @@ -47,6 +47,7 @@ require ( github.com/sijms/go-ora/v2 v2.9.0 github.com/snowflakedb/gosnowflake v1.18.1 github.com/spf13/cobra v1.10.1 + github.com/testcontainers/testcontainers-go v0.40.0 github.com/thlib/go-timezone-local v0.0.7 github.com/trinodb/trino-go-client v0.330.0 github.com/valkey-io/valkey-go v1.0.68 @@ -91,16 +92,19 @@ require ( cloud.google.com/go/iam v1.5.3 // indirect cloud.google.com/go/monitoring v1.24.3 // indirect cloud.google.com/go/trace v1.11.7 // indirect + dario.cat/mergo v1.0.2 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/BurntSushi/toml v1.4.0 // indirect github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.3 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/PuerkitoBio/goquery v1.10.3 // indirect github.com/VictoriaMetrics/easyproto v0.1.4 // indirect github.com/ajg/form v1.5.1 // indirect @@ -126,17 +130,29 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.4 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.38.4 // indirect github.com/aws/smithy-go v1.23.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect github.com/couchbase/gocbcore/v10 v10.8.1 // indirect github.com/couchbase/gocbcoreps v0.1.4 // indirect github.com/couchbase/goprotostellar v1.0.2 // indirect github.com/couchbase/tools-common/errors v1.0.0 // indirect github.com/couchbaselabs/gocbconnstr/v2 v2.0.0 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/danieljoos/wincred v1.2.2 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v28.5.1+incompatible // indirect + github.com/docker/go-connections v0.6.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.7.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -145,6 +161,7 @@ require ( github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/goccy/go-json v0.10.5 // indirect @@ -180,27 +197,47 @@ require ( github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.2.11 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.10 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/go-archive v0.1.0 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect + github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.7.1 // indirect + github.com/morikuni/aec v1.0.0 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/nakagami/chacha20 v0.1.0 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/shirou/gopsutil/v4 v4.25.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect + github.com/stretchr/testify v1.11.1 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zeebo/errs v1.4.0 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b // indirect @@ -233,6 +270,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/libc v1.66.10 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect diff --git a/go.sum b/go.sum index 65e485efe4..b552809dad 100644 --- a/go.sum +++ b/go.sum @@ -647,6 +647,8 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMb github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4= @@ -800,6 +802,14 @@ github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= github.com/couchbase/gocb/v2 v2.11.1 h1:xWDco7Qk/XSvGUjbUWRaXi0V35nsMijJnm4vHXN/rqY= github.com/couchbase/gocb/v2 v2.11.1/go.mod h1:aSh1Cmd1sPRpYyiBD5iWPehPWaTVF/oYhrtOAITWb/4= github.com/couchbase/gocbcore/v10 v10.8.1 h1:i4SnH0DH9APGC4GS2vS2m+3u08V7oJwviamOXdgAZOQ= @@ -816,8 +826,12 @@ github.com/couchbaselabs/gocaves/client v0.0.0-20250107114554-f96479220ae8 h1:MQ github.com/couchbaselabs/gocaves/client v0.0.0-20250107114554-f96479220ae8/go.mod h1:AVekAZwIY2stsJOMWLAS/0uA/+qdp7pjO8EHnl61QkY= github.com/couchbaselabs/gocbconnstr/v2 v2.0.0 h1:HU9DlAYYWR69jQnLN6cpg0fh0hxW/8d5hnglCXXjW78= github.com/couchbaselabs/gocbconnstr/v2 v2.0.0/go.mod h1:o7T431UOfFVHDNvMBUmUxpHnhivwv7BziUao/nMl81E= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0= github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -826,10 +840,12 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v28.4.0+incompatible h1:RBcf3Kjw2pMtwui5V0DIMdyeab8glEw5QY0UUU4C9kY= github.com/docker/cli v28.4.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v28.4.0+incompatible h1:KVC7bz5zJY/4AZe/78BIvCnPsLaC9T/zh72xnlrTTOk= -github.com/docker/docker v28.4.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM= +github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -840,6 +856,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dvsekhvalnov/jose2go v1.7.0 h1:bnQc8+GMnidJZA8zc6lLEAb4xNrIqHwO+9TzqvtQZPo= github.com/dvsekhvalnov/jose2go v1.7.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/elastic/elastic-transport-go/v8 v8.8.0 h1:7k1Ua+qluFr6p1jfJjGDl97ssJS/P7cHNInzfxgBQAo= github.com/elastic/elastic-transport-go/v8 v8.8.0/go.mod h1:YLHer5cj0csTzNFXoNQ8qhtGY1GTvSqPnKWKaqQE3Hk= github.com/elastic/go-elasticsearch/v9 v9.2.0 h1:COeL/g20+ixnUbffe4Wfbu88emrHjAq/LhVfmrjqRQs= @@ -913,6 +931,8 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= @@ -1174,9 +1194,13 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/looker-open-source/sdk-codegen/go v0.25.22 h1:DGYt1v2R2uE/m71sWAvgxsJnDLM9B7C40N5/CTDlE2A= github.com/looker-open-source/sdk-codegen/go v0.25.22/go.mod h1:Br1ntSiruDJ/4nYNjpYyWyCbqJ7+GQceWbIgn0hYims= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -1194,8 +1218,18 @@ github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8D github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= +github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= +github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1206,6 +1240,8 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/nakagami/chacha20 v0.1.0 h1:2fbf5KeVUw7oRpAe6/A7DqvBJLYYu0ka5WstFbnkEVo= @@ -1254,6 +1290,8 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= @@ -1275,6 +1313,8 @@ github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfF github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs= +github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sijms/go-ora/v2 v2.9.0 h1:+iQbUeTeCOFMb5BsOMgUhV8KWyrv9yjKpcK4x7+MFrg= @@ -1312,9 +1352,15 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU= +github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY= github.com/thlib/go-timezone-local v0.0.7 h1:fX8zd3aJydqLlTs/TrROrIIdztzsdFV23OzOQx31jII= github.com/thlib/go-timezone-local v0.0.7/go.mod h1:/Tnicc6m/lsJE0irFMA0LfIwTBo4QP7A8IfyIv4zZKI= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/trinodb/trino-go-client v0.330.0 h1:TBbHjFBuRjYbGtkNyRAJfzLOcwvz8ECihtMtxSzXqOc= github.com/trinodb/trino-go-client v0.330.0/go.mod h1:BXj9QNy6pA4Gn8eIu9dVdRhetABCjFAOZ6xxsVsOZJE= github.com/valkey-io/valkey-go v1.0.68 h1:bTbfonp49b41DqrF30q+y2JL3gcbjd2IiacFAtO4JBA= @@ -1347,6 +1393,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= @@ -1627,6 +1675,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1648,6 +1697,7 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1700,6 +1750,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -2129,6 +2180,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/prebuiltconfigs/prebuiltconfigs_test.go b/internal/prebuiltconfigs/prebuiltconfigs_test.go index 8bc6ef1e41..ce2e119bf6 100644 --- a/internal/prebuiltconfigs/prebuiltconfigs_test.go +++ b/internal/prebuiltconfigs/prebuiltconfigs_test.go @@ -21,6 +21,7 @@ import ( ) var expectedToolSources = []string{ + "alloydb-omni", "alloydb-postgres-admin", "alloydb-postgres-observability", "alloydb-postgres", @@ -99,36 +100,40 @@ func TestLoadPrebuiltToolYAMLs(t *testing.T) { } func TestGetPrebuiltTool(t *testing.T) { - alloydb_admin_config, _ := Get("alloydb-postgres-admin") - alloydb_observability_config, _ := Get("alloydb-postgres-observability") - alloydb_config, _ := Get("alloydb-postgres") - bigquery_config, _ := Get("bigquery") - clickhouse_config, _ := Get("clickhouse") - cloudsqlpg_observability_config, _ := Get("cloud-sql-postgres-observability") - cloudsqlpg_config, _ := Get("cloud-sql-postgres") - cloudsqlpg_admin_config, _ := Get("cloud-sql-postgres-admin") - cloudsqlmysql_admin_config, _ := Get("cloud-sql-mysql-admin") - cloudsqlmssql_admin_config, _ := Get("cloud-sql-mssql-admin") - cloudsqlmysql_observability_config, _ := Get("cloud-sql-mysql-observability") - cloudsqlmysql_config, _ := Get("cloud-sql-mysql") - cloudsqlmssql_observability_config, _ := Get("cloud-sql-mssql-observability") - cloudsqlmssql_config, _ := Get("cloud-sql-mssql") - dataplex_config, _ := Get("dataplex") - firestoreconfig, _ := Get("firestore") - looker_config, _ := Get("looker") - lookerca_config, _ := Get("looker-conversational-analytics") - mysql_config, _ := Get("mysql") - mssql_config, _ := Get("mssql") - oceanbase_config, _ := Get("oceanbase") - postgresconfig, _ := Get("postgres") - singlestore_config, _ := Get("singlestore") - spanner_config, _ := Get("spanner") - spannerpg_config, _ := Get("spanner-postgres") - mindsdb_config, _ := Get("mindsdb") - sqlite_config, _ := Get("sqlite") - neo4jconfig, _ := Get("neo4j") - healthcare_config, _ := Get("cloud-healthcare") - snowflake_config, _ := Get("snowflake") + alloydb_omni_config := getOrFatal(t, "alloydb-omni") + alloydb_admin_config := getOrFatal(t, "alloydb-postgres-admin") + alloydb_observability_config := getOrFatal(t, "alloydb-postgres-observability") + alloydb_config := getOrFatal(t, "alloydb-postgres") + bigquery_config := getOrFatal(t, "bigquery") + clickhouse_config := getOrFatal(t, "clickhouse") + cloudsqlpg_observability_config := getOrFatal(t, "cloud-sql-postgres-observability") + cloudsqlpg_config := getOrFatal(t, "cloud-sql-postgres") + cloudsqlpg_admin_config := getOrFatal(t, "cloud-sql-postgres-admin") + cloudsqlmysql_admin_config := getOrFatal(t, "cloud-sql-mysql-admin") + cloudsqlmssql_admin_config := getOrFatal(t, "cloud-sql-mssql-admin") + cloudsqlmysql_observability_config := getOrFatal(t, "cloud-sql-mysql-observability") + cloudsqlmysql_config := getOrFatal(t, "cloud-sql-mysql") + cloudsqlmssql_observability_config := getOrFatal(t, "cloud-sql-mssql-observability") + cloudsqlmssql_config := getOrFatal(t, "cloud-sql-mssql") + dataplex_config := getOrFatal(t, "dataplex") + firestoreconfig := getOrFatal(t, "firestore") + looker_config := getOrFatal(t, "looker") + lookerca_config := getOrFatal(t, "looker-conversational-analytics") + mysql_config := getOrFatal(t, "mysql") + mssql_config := getOrFatal(t, "mssql") + oceanbase_config := getOrFatal(t, "oceanbase") + postgresconfig := getOrFatal(t, "postgres") + singlestore_config := getOrFatal(t, "singlestore") + spanner_config := getOrFatal(t, "spanner") + spannerpg_config := getOrFatal(t, "spanner-postgres") + mindsdb_config := getOrFatal(t, "mindsdb") + sqlite_config := getOrFatal(t, "sqlite") + neo4jconfig := getOrFatal(t, "neo4j") + healthcare_config := getOrFatal(t, "cloud-healthcare") + snowflake_config := getOrFatal(t, "snowflake") + if len(alloydb_omni_config) <= 0 { + t.Fatalf("unexpected error: could not fetch alloydb omni prebuilt tools yaml") + } if len(alloydb_admin_config) <= 0 { t.Fatalf("unexpected error: could not fetch alloydb admin prebuilt tools yaml") } @@ -233,3 +238,11 @@ func TestFailGetPrebuiltTool(t *testing.T) { t.Fatalf("unexpected an error but got nil.") } } + +func getOrFatal(t *testing.T, prebuiltSourceConfig string) []byte { + bytes, err := Get(prebuiltSourceConfig) + if err != nil { + t.Fatalf("Cannot get prebuilt config for %q, error %v", prebuiltSourceConfig, err) + } + return bytes +} diff --git a/internal/prebuiltconfigs/tools/alloydb-omni.yaml b/internal/prebuiltconfigs/tools/alloydb-omni.yaml new file mode 100644 index 0000000000..9fac9a32e7 --- /dev/null +++ b/internal/prebuiltconfigs/tools/alloydb-omni.yaml @@ -0,0 +1,277 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +sources: + alloydb-omni-source: + kind: postgres + host: ${ALLOYDB_OMNI_HOST:localhost} + port: ${ALLOYDB_OMNI_PORT:5432} + database: ${ALLOYDB_OMNI_DATABASE} + user: ${ALLOYDB_OMNI_USER} + password: ${ALLOYDB_OMNI_PASSWORD:} + queryParams: ${ALLOYDB_OMNI_QUERY_PARAMS:} + +tools: + execute_sql: + kind: postgres-execute-sql + source: alloydb-omni-source + description: Use this tool to execute sql. + + list_tables: + kind: postgres-list-tables + source: alloydb-omni-source + description: "Lists detailed schema information (object type, columns, constraints, indexes, triggers, owner, comment) as JSON for user-created tables (ordinary or partitioned). Filters by a comma-separated list of names. If names are omitted, lists all tables in user schemas." + + list_active_queries: + kind: postgres-list-active-queries + source: alloydb-omni-source + description: "List the top N (default 50) currently running queries (state='active') from pg_stat_activity, ordered by longest-running first. Returns pid, user, database, application_name, client_addr, state, wait_event_type/wait_event, backend/xact/query start times, computed query_duration, and the SQL text." + + list_available_extensions: + kind: postgres-list-available-extensions + source: alloydb-omni-source + description: "Discover all PostgreSQL extensions available for installation on this server, returning name, default_version, and description." + + list_installed_extensions: + kind: postgres-list-installed-extensions + source: alloydb-omni-source + description: "List all installed PostgreSQL extensions with their name, version, schema, owner, and description." + + long_running_transactions: + kind: postgres-long-running-transactions + source: alloydb-omni-source + + list_locks: + kind: postgres-list-locks + source: alloydb-omni-source + + replication_stats: + kind: postgres-replication-stats + source: alloydb-omni-source + + list_autovacuum_configurations: + kind: postgres-sql + source: alloydb-omni-source + description: "List PostgreSQL autovacuum-related configurations (name and current setting) from pg_settings." + statement: | + SELECT name, + setting + FROM pg_settings + WHERE category = 'Autovacuum'; + + list_columnar_configurations: + kind: postgres-sql + source: alloydb-omni-source + description: "List AlloyDB Omni columnar-related configurations (name and current setting) from pg_settings." + statement: | + SELECT name, + setting + FROM pg_settings + WHERE name like 'google_columnar_engine.%'; + + list_columnar_recommended_columns: + kind: postgres-sql + source: alloydb-omni-source + description: "Lists columns that AlloyDB Omni recommends adding to the columnar engine to improve query performance." + statement: select * from g_columnar_recommended_columns; + + list_memory_configurations: + kind: postgres-sql + source: alloydb-omni-source + description: "List PostgreSQL memory-related configurations (name and current setting) from pg_settings." + statement: | + ( + SELECT + name, + pg_size_pretty((setting::bigint * 1024)::bigint) setting + FROM pg_settings + WHERE name IN ('work_mem', 'maintenance_work_mem') + ) + UNION ALL + ( + SELECT + name, + pg_size_pretty((((setting::bigint) * 8) * 1024)::bigint) + FROM pg_settings + WHERE name IN ('shared_buffers', 'wal_buffers', 'effective_cache_size', 'temp_buffers') + ) + ORDER BY 1 DESC; + + list_top_bloated_tables: + kind: postgres-sql + source: alloydb-omni-source + description: | + List the top tables by dead-tuple (approximate bloat signal), returning schema, table, live/dead tuples, percentage, and last vacuum/analyze times. + statement: | + SELECT + schemaname AS schema_name, + relname AS relation_name, + n_live_tup AS live_tuples, + n_dead_tup AS dead_tuples, + TRUNC((n_dead_tup::NUMERIC / NULLIF(n_live_tup + n_dead_tup, 0)) * 100, 2) AS dead_tuple_percentage, + last_vacuum, + last_autovacuum, + last_analyze, + last_autoanalyze + FROM pg_stat_user_tables + ORDER BY n_dead_tup DESC + LIMIT COALESCE($1::int, 50); + parameters: + - name: limit + description: "The maximum number of results to return." + type: integer + default: 50 + + list_replication_slots: + kind: postgres-sql + source: alloydb-omni-source + description: "List key details for all PostgreSQL replication slots (e.g., type, database, active status) and calculates the size of the outstanding WAL that is being prevented from removal by the slot." + statement: | + SELECT + slot_name, + slot_type, + plugin, + database, + temporary, + active, + restart_lsn, + confirmed_flush_lsn, + xmin, + catalog_xmin, + pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal + FROM pg_replication_slots; + + list_invalid_indexes: + kind: postgres-sql + source: alloydb-omni-source + description: "Lists all invalid PostgreSQL indexes which are taking up disk space but are unusable by the query planner. Typically created by failed CREATE INDEX CONCURRENTLY operations." + statement: | + SELECT + nspname AS schema_name, + indexrelid::regclass AS index_name, + indrelid::regclass AS table_name, + pg_size_pretty(pg_total_relation_size(indexrelid)) AS index_size, + indisready, + indisvalid, + pg_get_indexdef(pg_class.oid) AS index_def + FROM pg_index + JOIN pg_class ON pg_class.oid = pg_index.indexrelid + JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace + WHERE indisvalid = FALSE; + + get_query_plan: + kind: postgres-sql + source: alloydb-omni-source + description: "Generate a PostgreSQL EXPLAIN plan in JSON format for a single SQL statement—without executing it. This returns the optimizer's estimated plan, costs, and rows (no ANALYZE, no extra options). Use in production safely for plan inspection, regression checks, and query tuning workflows." + statement: | + EXPLAIN (FORMAT JSON) {{.query}}; + templateParameters: + - name: query + type: string + description: "The SQL statement for which you want to generate plan (omit the EXPLAIN keyword)." + required: true + + list_views: + kind: postgres-list-views + source: alloydb-omni-source + + list_schemas: + kind: postgres-list-schemas + source: alloydb-omni-source + + list_indexes: + kind: postgres-list-indexes + source: alloydb-omni-source + + list_sequences: + kind: postgres-list-sequences + source: alloydb-omni-source + + database_overview: + kind: postgres-database-overview + source: alloydb-omni-source + + list_triggers: + kind: postgres-list-triggers + source: alloydb-omni-source + + list_query_stats: + kind: postgres-list-query-stats + source: alloydb-omni-source + + get_column_cardinality: + kind: postgres-get-column-cardinality + source: alloydb-omni-source + + list_table_stats: + kind: postgres-list-table-stats + source: alloydb-omni-source + + list_publication_tables: + kind: postgres-list-publication-tables + source: alloydb-omni-source + + list_tablespaces: + kind: postgres-list-tablespaces + source: alloydb-omni-source + + list_pg_settings: + kind: postgres-list-pg-settings + source: alloydb-omni-source + + list_database_stats: + kind: postgres-list-database-stats + source: alloydb-omni-source + + list_roles: + kind: postgres-list-roles + source: alloydb-omni-source + + list_stored_procedure: + kind: postgres-list-stored-procedure + source: alloydb-omni-source + +toolsets: + alloydb_omni_database_tools: + - execute_sql + - list_tables + - list_active_queries + - list_available_extensions + - list_installed_extensions + - list_autovacuum_configurations + - list_columnar_configurations + - list_columnar_recommended_columns + - list_memory_configurations + - list_top_bloated_tables + - list_replication_slots + - list_invalid_indexes + - get_query_plan + - list_views + - list_schemas + - database_overview + - list_triggers + - list_indexes + - list_sequences + - long_running_transactions + - list_locks + - replication_stats + - list_query_stats + - get_column_cardinality + - list_publication_tables + - list_tablespaces + - list_pg_settings + - list_database_stats + - list_roles + - list_table_stats + - list_stored_procedure diff --git a/tests/alloydbomni/alloydb_omni_integration_test.go b/tests/alloydbomni/alloydb_omni_integration_test.go new file mode 100644 index 0000000000..b634789ce9 --- /dev/null +++ b/tests/alloydbomni/alloydb_omni_integration_test.go @@ -0,0 +1,157 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package alloydbomni + +import ( + "context" + "fmt" + "net/url" + "os" + "regexp" + "testing" + "time" + + "github.com/googleapis/genai-toolbox/internal/testutils" + "github.com/googleapis/genai-toolbox/tests" + "github.com/jackc/pgx/v5/pgxpool" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" +) + +var ( + AlloyDBUser = "postgres" + AlloyDBPass = "mysecretpassword" + AlloyDBDatabase = "postgres" +) + +// Copied over from postgres.go +func initPostgresConnectionPool(host, port, user, pass, dbname string) (*pgxpool.Pool, error) { + // urlExample := "postgres:dd//username:password@localhost:5432/database_name" + url := &url.URL{ + Scheme: "postgres", + User: url.UserPassword(user, pass), + Host: fmt.Sprintf("%s:%s", host, port), + Path: dbname, + } + pool, err := pgxpool.New(context.Background(), url.String()) + if err != nil { + return nil, fmt.Errorf("Unable to create connection pool: %w", err) + } + + return pool, nil +} + +func setupAlloyDBContainer(ctx context.Context, t *testing.T) (string, string, func()) { + t.Helper() + + req := testcontainers.ContainerRequest{ + Image: "google/alloydbomni:16.9.0-ubi9", // Pinning version for stability + ExposedPorts: []string{"5432/tcp"}, + Env: map[string]string{ + "POSTGRES_PASSWORD": AlloyDBPass, + }, + WaitingFor: wait.ForAll( + wait.ForLog("Post Startup: Successfully reinstalled extensions"), + wait.ForExposedPort(), + ), + } + + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + t.Fatalf("failed to start alloydb container: %s", err) + } + + cleanup := func() { + if err := container.Terminate(ctx); err != nil { + t.Fatalf("failed to terminate container: %s", err) + } + } + + host, err := container.Host(ctx) + if err != nil { + cleanup() + t.Fatalf("failed to get container host: %s", err) + } + + mappedPort, err := container.MappedPort(ctx, "5432") + if err != nil { + cleanup() + t.Fatalf("failed to get container mapped port: %s", err) + } + + return host, mappedPort.Port(), cleanup +} + +func TestAlloyDBOmni(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + + AlloyDBHost, AlloyDBPort, containerCleanup := setupAlloyDBContainer(ctx, t) + defer containerCleanup() + + os.Setenv("ALLOYDB_OMNI_HOST", AlloyDBHost) + os.Setenv("ALLOYDB_OMNI_PORT", AlloyDBPort) + os.Setenv("ALLOYDB_OMNI_USER", AlloyDBUser) + os.Setenv("ALLOYDB_OMNI_PASSWORD", AlloyDBPass) + os.Setenv("ALLOYDB_OMNI_DATABASE", AlloyDBDatabase) + + args := []string{"--prebuilt", "alloydb-omni"} + + pool, err := initPostgresConnectionPool(AlloyDBHost, AlloyDBPort, AlloyDBUser, AlloyDBPass, AlloyDBDatabase) + if err != nil { + t.Fatalf("unable to create alloydb connection pool: %s", err) + } + + cmd, cleanup, err := tests.StartCmd(ctx, map[string]any{}, args...) + if err != nil { + t.Fatalf("command initialization returned an error: %s", err) + } + defer cleanup() + + // Wait for server to be ready + waitCtx, waitCancel := context.WithTimeout(ctx, 30*time.Second) + defer waitCancel() + + out, err := testutils.WaitForString(waitCtx, regexp.MustCompile(`Server ready to serve`), cmd.Out) + if err != nil { + t.Logf("toolbox command logs: \n%s", out) + t.Fatalf("toolbox didn't start successfully: %s", err) + } + + // Run Postgres prebuilt tool tests + tests.RunPostgresListViewsTest(t, ctx, pool) + tests.RunPostgresListSchemasTest(t, ctx, pool) + tests.RunPostgresListActiveQueriesTest(t, ctx, pool) + tests.RunPostgresListAvailableExtensionsTest(t) + tests.RunPostgresListInstalledExtensionsTest(t) + tests.RunPostgresDatabaseOverviewTest(t, ctx, pool) + tests.RunPostgresListTriggersTest(t, ctx, pool) + tests.RunPostgresListIndexesTest(t, ctx, pool) + tests.RunPostgresListSequencesTest(t, ctx, pool) + tests.RunPostgresLongRunningTransactionsTest(t, ctx, pool) + tests.RunPostgresListLocksTest(t, ctx, pool) + tests.RunPostgresReplicationStatsTest(t, ctx, pool) + tests.RunPostgresGetColumnCardinalityTest(t, ctx, pool) + tests.RunPostgresListTableStatsTest(t, ctx, pool) + tests.RunPostgresListPublicationTablesTest(t, ctx, pool) + tests.RunPostgresListTableSpacesTest(t) + tests.RunPostgresListPgSettingsTest(t, ctx, pool) + tests.RunPostgresListDatabaseStatsTest(t, ctx, pool) + tests.RunPostgresListRolesTest(t, ctx, pool) + tests.RunPostgresListStoredProcedureTest(t, ctx, pool) +}