From c5622ed5029813a84a75c8a7892b732703ac14b6 Mon Sep 17 00:00:00 2001 From: Averi Kitsch Date: Wed, 4 Mar 2026 15:42:20 -0800 Subject: [PATCH 1/8] feat(source/alloydb): restructure prebuilt toolsets and add statement tools tests --- cmd/internal/tools_file_test.go | 50 ++++- .../prebuiltconfigs/tools/alloydb-omni.yaml | 72 ++---- .../tools/alloydb-postgres.yaml | 209 ++++++++++++++---- .../alloydb_omni_integration_test.go | 12 + .../alloydbpg/alloydb_pg_integration_test.go | 33 +++ tests/tool.go | 82 +++---- 6 files changed, 302 insertions(+), 156 deletions(-) diff --git a/cmd/internal/tools_file_test.go b/cmd/internal/tools_file_test.go index 6aaf198ac27c..8d30cadcd4dd 100644 --- a/cmd/internal/tools_file_test.go +++ b/cmd/internal/tools_file_test.go @@ -1621,9 +1621,21 @@ func TestPrebuiltTools(t *testing.T) { 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"}, + "data": tools.ToolsetConfig{ + Name: "data", + ToolNames: []string{"execute_sql", "list_tables", "list_views", "list_schemas", "get_query_plan", "list_indexes", "list_sequences", "list_stored_procedure"}, + }, + "monitor": tools.ToolsetConfig{ + Name: "monitor", + ToolNames: []string{"database_overview", "list_active_queries", "long_running_transactions", "list_locks", "list_database_stats", "replication_stats", "list_replication_slots"}, + }, + "config": tools.ToolsetConfig{ + Name: "config", + ToolNames: []string{"list_columnar_configurations", "list_columnar_recommended_columns", "list_memory_configurations", "list_pg_settings", "list_available_extensions", "list_installed_extensions", "list_roles"}, + }, + "optimize": tools.ToolsetConfig{ + Name: "optimize", + ToolNames: []string{"list_query_stats", "list_table_stats", "get_column_cardinality", "list_top_bloated_tables", "list_invalid_indexes", "list_autovacuum_configurations"}, }, }, }, @@ -1671,9 +1683,25 @@ func TestPrebuiltTools(t *testing.T) { name: "alloydb prebuilt tools", in: alloydb_config, wantToolset: server.ToolsetConfigs{ - "alloydb_postgres_database_tools": tools.ToolsetConfig{ - Name: "alloydb_postgres_database_tools", - ToolNames: []string{"execute_sql", "list_tables", "list_active_queries", "list_available_extensions", "list_installed_extensions", "list_autovacuum_configurations", "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"}, + "admin": tools.ToolsetConfig{ + Name: "admin", + ToolNames: []string{"create_cluster", "get_cluster", "list_clusters", "create_instance", "get_instance", "list_instances", "create_user", "wait_for_operation"}, + }, + "data": tools.ToolsetConfig{ + Name: "data", + ToolNames: []string{"execute_sql", "list_tables", "list_views", "list_schemas", "get_query_plan", "list_stored_procedure", "list_sequences", "list_indexes"}, + }, + "monitor": tools.ToolsetConfig{ + Name: "monitor", + ToolNames: []string{"database_overview", "list_active_queries", "long_running_transactions", "list_locks", "get_system_metrics", "get_query_metrics", "list_database_stats"}, + }, + "optimize": tools.ToolsetConfig{ + Name: "optimize", + ToolNames: []string{"list_query_stats", "list_table_stats", "get_column_cardinality", "list_top_bloated_tables", "list_invalid_indexes", "list_autovacuum_configurations"}, + }, + "config": tools.ToolsetConfig{ + Name: "config", + ToolNames: []string{"list_available_extensions", "list_installed_extensions", "list_pg_settings", "list_memory_configurations", "list_roles", "replication_stats", "list_replication_slots", "list_publication_tables"}, }, }, }, @@ -1960,6 +1988,16 @@ func TestPrebuiltTools(t *testing.T) { if len(toolsFile.Prompts) != 0 { t.Fatalf("expected empty prompts map for prebuilt config, got: %v", toolsFile.Prompts) } + + + t.Run("check toolset sizes", func(t *testing.T) { + for tsName, ts := range toolsFile.Toolsets { + if len(ts.ToolNames) > 10 { + t.Logf("WARNING: Toolset %q in config %q has %d tools, which is larger than the recommended maximum of 10.", tsName, tc.name, len(ts.ToolNames)) + fmt.Printf("WARNING: Toolset %q in config %q has %d tools, which is larger than the recommended maximum of 10.\n", tsName, tc.name, len(ts.ToolNames)) + } + } + }) }) } } diff --git a/internal/prebuiltconfigs/tools/alloydb-omni.yaml b/internal/prebuiltconfigs/tools/alloydb-omni.yaml index 9fac9a32e7b1..85ffa4e96312 100644 --- a/internal/prebuiltconfigs/tools/alloydb-omni.yaml +++ b/internal/prebuiltconfigs/tools/alloydb-omni.yaml @@ -21,45 +21,36 @@ sources: 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 @@ -69,7 +60,6 @@ tools: setting FROM pg_settings WHERE category = 'Autovacuum'; - list_columnar_configurations: kind: postgres-sql source: alloydb-omni-source @@ -79,13 +69,11 @@ tools: 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 @@ -107,7 +95,6 @@ tools: 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 @@ -132,7 +119,6 @@ tools: description: "The maximum number of results to return." type: integer default: 50 - list_replication_slots: kind: postgres-sql source: alloydb-omni-source @@ -151,7 +137,6 @@ tools: 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 @@ -169,7 +154,6 @@ tools: 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 @@ -181,97 +165,81 @@ tools: 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: + data: - 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 + - get_query_plan - list_indexes - list_sequences + - list_stored_procedure + monitor: + - database_overview + - list_active_queries - long_running_transactions - list_locks + - list_database_stats - replication_stats - - list_query_stats - - get_column_cardinality - - list_publication_tables - - list_tablespaces + - list_replication_slots + config: + - list_columnar_configurations + - list_columnar_recommended_columns + - list_memory_configurations - list_pg_settings - - list_database_stats + - list_available_extensions + - list_installed_extensions - list_roles + optimize: + - list_query_stats - list_table_stats - - list_stored_procedure + - get_column_cardinality + - list_top_bloated_tables + - list_invalid_indexes + - list_autovacuum_configurations diff --git a/internal/prebuiltconfigs/tools/alloydb-postgres.yaml b/internal/prebuiltconfigs/tools/alloydb-postgres.yaml index a96a3bca9fc0..a6b4a72953f8 100644 --- a/internal/prebuiltconfigs/tools/alloydb-postgres.yaml +++ b/internal/prebuiltconfigs/tools/alloydb-postgres.yaml @@ -23,45 +23,41 @@ sources: user: ${ALLOYDB_POSTGRES_USER:} password: ${ALLOYDB_POSTGRES_PASSWORD:} ipType: ${ALLOYDB_POSTGRES_IP_TYPE:public} - + cloud-monitoring-source: + kind: cloud-monitoring + alloydb-admin-source: + kind: alloydb-admin + defaultProject: ${ALLOYDB_POSTGRES_PROJECT:} tools: execute_sql: kind: postgres-execute-sql source: alloydb-pg-source description: Use this tool to execute sql. - list_tables: kind: postgres-list-tables source: alloydb-pg-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-pg-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-pg-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-pg-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-pg-source - list_locks: kind: postgres-list-locks source: alloydb-pg-source - replication_stats: kind: postgres-replication-stats source: alloydb-pg-source - list_autovacuum_configurations: kind: postgres-sql source: alloydb-pg-source @@ -71,7 +67,6 @@ tools: setting FROM pg_settings WHERE category = 'Autovacuum'; - list_memory_configurations: kind: postgres-sql source: alloydb-pg-source @@ -93,7 +88,6 @@ tools: 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-pg-source @@ -118,7 +112,6 @@ tools: description: "The maximum number of results to return." type: integer default: 50 - list_replication_slots: kind: postgres-sql source: alloydb-pg-source @@ -137,7 +130,6 @@ tools: 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-pg-source @@ -155,7 +147,6 @@ tools: 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-pg-source @@ -167,95 +158,217 @@ tools: 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-pg-source - list_schemas: kind: postgres-list-schemas source: alloydb-pg-source - list_indexes: kind: postgres-list-indexes source: alloydb-pg-source - list_sequences: kind: postgres-list-sequences source: alloydb-pg-source - database_overview: kind: postgres-database-overview source: alloydb-pg-source - list_triggers: kind: postgres-list-triggers source: alloydb-pg-source - list_query_stats: kind: postgres-list-query-stats source: alloydb-pg-source - get_column_cardinality: kind: postgres-get-column-cardinality source: alloydb-pg-source - list_table_stats: kind: postgres-list-table-stats source: alloydb-pg-source - list_publication_tables: kind: postgres-list-publication-tables source: alloydb-pg-source - list_tablespaces: kind: postgres-list-tablespaces source: alloydb-pg-source - list_pg_settings: kind: postgres-list-pg-settings source: alloydb-pg-source - list_database_stats: kind: postgres-list-database-stats source: alloydb-pg-source - list_roles: kind: postgres-list-roles source: alloydb-pg-source - list_stored_procedure: kind: postgres-list-stored-procedure source: alloydb-pg-source + get_system_metrics: + kind: cloud-monitoring-query-prometheus + source: cloud-monitoring-source + description: | + Fetches system level cloudmonitoring data (timeseries metrics) for an AlloyDB cluster, instance. + To use this tool, you must provide the Google Cloud `projectId` and a PromQL `query`. + + Generate the PromQL `query` for AlloyDB system metrics using the provided metrics and rules. Get labels like `cluster_id` and `instance_id` from the user's intent. + + Defaults: + 1. Interval: Use a default interval of `5m` for `_over_time` aggregation functions unless a different window is specified by the user. + + PromQL Query Examples: + 1. Basic Time Series: `avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance"}[5m])` + 2. Top K: `topk(30, avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance"}[5m]))` + 3. Mean: `avg(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="my-instance","cluster_id"="my-cluster"}[5m]))` + 4. Minimum: `min(min_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 5. Maximum: `max(max_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 6. Sum: `sum(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 7. Count streams: `count(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 8. Percentile with groupby on instanceid, clusterid: `quantile by ("instance_id","cluster_id")(0.99,avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","cluster_id"="my-cluster","instance_id"="my-instance"}[5m]))` + + Available Metrics List: metricname. description. monitored resource. labels + 1. `alloydb.googleapis.com/instance/cpu/average_utilization`: The percentage of CPU being used on an instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 2. `alloydb.googleapis.com/instance/cpu/maximum_utilization`: Maximum CPU utilization across all currently serving nodes of the instance from 0 to 100. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 3. `alloydb.googleapis.com/cluster/storage/usage`: The total AlloyDB storage in bytes across the entire cluster. `alloydb.googleapis.com/Cluster`. `cluster_id`. + 4. `alloydb.googleapis.com/instance/postgres/replication/replicas`: The number of read replicas connected to the primary instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `state`, `replica_instance_id`. + 5. `alloydb.googleapis.com/instance/postgres/replication/maximum_lag`: The maximum replication time lag calculated across all serving read replicas of the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `replica_instance_id`. + 6. `alloydb.googleapis.com/instance/memory/min_available_memory`: The minimum available memory across all currently serving nodes of the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 7. `alloydb.googleapis.com/instance/postgres/instances`: The number of nodes in the instance, along with their status, which can be either up or down. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `status`. + 8. `alloydb.googleapis.com/database/postgresql/tuples`: Number of tuples (rows) by state per database in the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`, `state`. + 9. `alloydb.googleapis.com/database/postgresql/temp_bytes_written_for_top_databases`: The total amount of data(in bytes) written to temporary files by the queries per database for top 500 dbs. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 10. `alloydb.googleapis.com/database/postgresql/temp_files_written_for_top_databases`: The number of temporary files used for writing data per database while performing internal algorithms like join, sort etc for top 500 dbs. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 11. `alloydb.googleapis.com/database/postgresql/inserted_tuples_count_for_top_databases`: The total number of rows inserted per db for top 500 dbs as a result of the queries in the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 12. `alloydb.googleapis.com/database/postgresql/updated_tuples_count_for_top_databases`: The total number of rows updated per db for top 500 dbs as a result of the queries in the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 13. `alloydb.googleapis.com/database/postgresql/deleted_tuples_count_for_top_databases`: The total number of rows deleted per db for top 500 dbs as a result of the queries in the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 14. `alloydb.googleapis.com/database/postgresql/backends_for_top_databases`: The current number of connections per database to the instance for top 500 dbs. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 15. `alloydb.googleapis.com/instance/postgresql/backends_by_state`: The current number of connections to the instance grouped by the state like idle, active, idle_in_transaction, idle_in_transaction_aborted, disabled, and fastpath_function_call. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `state`. + 16. `alloydb.googleapis.com/instance/postgresql/backends_for_top_applications`: The current number of connections to the AlloyDB instance, grouped by applications for top 500 applications. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `application_name`. + 17. `alloydb.googleapis.com/database/postgresql/new_connections_for_top_databases`: Total number of new connections added per database for top 500 databases to the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 18. `alloydb.googleapis.com/database/postgresql/deadlock_count_for_top_databases`: Total number of deadlocks detected in the instance per database for top 500 dbs. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 19. `alloydb.googleapis.com/database/postgresql/statements_executed_count`: Total count of statements executed in the instance per database per operation_type. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`, `operation_type`. + 20. `alloydb.googleapis.com/instance/postgresql/returned_tuples_count`: Number of rows scanned while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 21. `alloydb.googleapis.com/instance/postgresql/fetched_tuples_count`: Number of rows fetched while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 22. `alloydb.googleapis.com/instance/postgresql/updated_tuples_count`: Number of rows updated while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 23. `alloydb.googleapis.com/instance/postgresql/inserted_tuples_count`: Number of rows inserted while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 24. `alloydb.googleapis.com/instance/postgresql/deleted_tuples_count`: Number of rows deleted while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 25. `alloydb.googleapis.com/instance/postgresql/written_tuples_count`: Number of rows written while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 26. `alloydb.googleapis.com/instance/postgresql/deadlock_count`: Number of deadlocks detected in the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 27. `alloydb.googleapis.com/instance/postgresql/blks_read`: Number of blocks read by Postgres that were not in the buffer cache. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 28. `alloydb.googleapis.com/instance/postgresql/blks_hit`: Number of times Postgres found the requested block in the buffer cache. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 29. `alloydb.googleapis.com/instance/postgresql/temp_bytes_written_count`: The total amount of data(in bytes) written to temporary files by the queries while performing internal algorithms like join, sort etc. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 30. `alloydb.googleapis.com/instance/postgresql/temp_files_written_count`: The number of temporary files used for writing data in the instance while performing internal algorithms like join, sort etc. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 31. `alloydb.googleapis.com/instance/postgresql/new_connections_count`: The number new connections added to the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 32. `alloydb.googleapis.com/instance/postgresql/wait_count`: Total number of times processes waited for each wait event in the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `wait_event_type`, `wait_event_name`. + 33. `alloydb.googleapis.com/instance/postgresql/wait_time`: Total elapsed wait time for each wait event in the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `wait_event_type`, `wait_event_name`. + 34. `alloydb.googleapis.com/instance/postgres/transaction_count`: The number of committed and rolled back transactions across all serving nodes of the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + list_clusters: + kind: alloydb-list-clusters + source: alloydb-admin-source + create_cluster: + kind: alloydb-create-cluster + source: alloydb-admin-source + create_user: + kind: alloydb-create-user + source: alloydb-admin-source + wait_for_operation: + kind: alloydb-wait-for-operation + source: alloydb-admin-source + delay: 1s + maxDelay: 4m + multiplier: 2 + maxRetries: 10 + get_query_metrics: + kind: cloud-monitoring-query-prometheus + source: cloud-monitoring-source + description: | + Fetches query level cloudmonitoring data (timeseries metrics) for queries running in an AlloyDB instance. + To use this tool, you must provide the Google Cloud `projectId` and a PromQL `query`. + + Generate the PromQL `query` for AlloyDB query metrics using the provided metrics and rules. Get labels like `cluster_id`, `instance_id`, and `query_hash` from the user's intent. If `query_hash` is provided, use the per-query metrics. + Defaults: + 1. Interval: Use a default interval of `5m` for `_over_time` aggregation functions unless a different window is specified by the user. + + PromQL Query Examples: + 1. Basic Time Series: `avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance"}[5m])` + 2. Top K: `topk(30, avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance"}[5m]))` + 3. Mean: `avg(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="my-instance","cluster_id"="my-cluster"}[5m]))` + 4. Minimum: `min(min_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 5. Maximum: `max(max_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 6. Sum: `sum(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 7. Count streams: `count(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 8. Percentile with groupby on instanceid, clusterid: `quantile by ("instance_id","cluster_id")(0.99,avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","cluster_id"="my-cluster","instance_id"="my-instance"}[5m]))` + + Available Metrics List: metricname. description. monitored resource. labels. aggregate is the aggregated values for all query stats, Use aggregate metrics if query id is not provided. For perquery metrics do not fetch querystring unless specified by user specifically. Have the aggregation on query hash to avoid fetching the querystring. Do not use latency metrics for anything. + 1. `alloydb.googleapis.com/database/postgresql/insights/aggregate/latencies`: Aggregated query latency distribution. `alloydb.googleapis.com/Database`. `user`, `client_addr`. + 2. `alloydb.googleapis.com/database/postgresql/insights/aggregate/execution_time`: Accumulated aggregated query execution time since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`. + 3. `alloydb.googleapis.com/database/postgresql/insights/aggregate/io_time`: Accumulated aggregated IO time since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `io_type`. + 4. `alloydb.googleapis.com/database/postgresql/insights/aggregate/lock_time`: Accumulated aggregated lock wait time since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `lock_type`. + 5. `alloydb.googleapis.com/database/postgresql/insights/aggregate/row_count`: Aggregated number of retrieved or affected rows since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`. + 6. `alloydb.googleapis.com/database/postgresql/insights/aggregate/shared_blk_access_count`: Aggregated shared blocks accessed by statement execution. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `access_type`. + 7. `alloydb.googleapis.com/database/postgresql/insights/perquery/latencies`: Per query latency distribution. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `querystring`, `query_hash`. + 8. `alloydb.googleapis.com/database/postgresql/insights/perquery/execution_time`: Accumulated execution times per user per database per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `querystring`, `query_hash`. + 9. `alloydb.googleapis.com/database/postgresql/insights/perquery/io_time`: Accumulated IO time since the last sample per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `io_type`, `querystring`, `query_hash`. + 10. `alloydb.googleapis.com/database/postgresql/insights/perquery/lock_time`: Accumulated lock wait time since the last sample per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `lock_type`, `querystring`, `query_hash`. + 11. `alloydb.googleapis.com/database/postgresql/insights/perquery/row_count`: The number of retrieved or affected rows since the last sample per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `querystring`, `query_hash`. + 12. `alloydb.googleapis.com/database/postgresql/insights/perquery/shared_blk_access_count`: Shared blocks accessed by statement execution per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `access_type`, `querystring`, `query_hash`. + 13. `alloydb.googleapis.com/database/postgresql/insights/pertag/latencies`: Query latency distribution. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`. + 14. `alloydb.googleapis.com/database/postgresql/insights/pertag/execution_time`: Accumulated execution times since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`. + 15. `alloydb.googleapis.com/database/postgresql/insights/pertag/io_time`: Accumulated IO time since the last sample per tag. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `io_type`, `tag_hash`. + 16. `alloydb.googleapis.com/database/postgresql/insights/pertag/lock_time`: Accumulated lock wait time since the last sample per tag. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `lock_type`, `tag_hash`. + 17. `alloydb.googleapis.com/database/postgresql/insights/pertag/shared_blk_access_count`: Shared blocks accessed by statement execution per tag. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `access_type`, `tag_hash`. + 18. `alloydb.googleapis.com/database/postgresql/insights/pertag/row_count`: The number of retrieved or affected rows since the last sample per tag. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`. + get_instance: + kind: alloydb-get-instance + source: alloydb-admin-source + get_cluster: + kind: alloydb-get-cluster + source: alloydb-admin-source + create_instance: + kind: alloydb-create-instance + source: alloydb-admin-source + list_instances: + kind: alloydb-list-instances + source: alloydb-admin-source toolsets: - alloydb_postgres_database_tools: + admin: + - create_cluster + - get_cluster + - list_clusters + - create_instance + - get_instance + - list_instances + - create_user + - wait_for_operation + data: - execute_sql - list_tables - - list_active_queries - - list_available_extensions - - list_installed_extensions - - list_autovacuum_configurations - - 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 + - get_query_plan + - list_stored_procedure - list_sequences + - list_indexes + monitor: + - database_overview + - list_active_queries - long_running_transactions - list_locks - - replication_stats + - get_system_metrics + - get_query_metrics + - list_database_stats + optimize: - list_query_stats + - list_table_stats - get_column_cardinality - - list_publication_tables - - list_tablespaces + - list_top_bloated_tables + - list_invalid_indexes + - list_autovacuum_configurations + config: + - list_available_extensions + - list_installed_extensions - list_pg_settings - - list_database_stats + - list_memory_configurations - list_roles - - list_table_stats - - list_stored_procedure + - replication_stats + - list_replication_slots + - list_publication_tables diff --git a/tests/alloydbomni/alloydb_omni_integration_test.go b/tests/alloydbomni/alloydb_omni_integration_test.go index 7f1ebf4ebdda..4dd7743786b1 100644 --- a/tests/alloydbomni/alloydb_omni_integration_test.go +++ b/tests/alloydbomni/alloydb_omni_integration_test.go @@ -162,4 +162,16 @@ func TestAlloyDBOmni(t *testing.T) { tests.RunPostgresListDatabaseStatsTest(t, ctx, pool) tests.RunPostgresListRolesTest(t, ctx, pool) tests.RunPostgresListStoredProcedureTest(t, ctx, pool) + + toolsToTest := map[string]string{ + "list_autovacuum_configurations": `{}`, + "list_memory_configurations": `{}`, + "list_top_bloated_tables": `{"limit": 10}`, + "list_replication_slots": `{}`, + "list_invalid_indexes": `{}`, + "get_query_plan": `{"query": "SELECT 1"}`, + "list_columnar_configurations": `{}`, + "list_columnar_recommended_columns": `{}`, + } + tests.RunStatementToolsTest(t, toolsToTest) } diff --git a/tests/alloydbpg/alloydb_pg_integration_test.go b/tests/alloydbpg/alloydb_pg_integration_test.go index 057f955c0bbd..40a9c6dbdf66 100644 --- a/tests/alloydbpg/alloydb_pg_integration_test.go +++ b/tests/alloydbpg/alloydb_pg_integration_test.go @@ -217,6 +217,39 @@ func TestAlloyDBPgToolEndpoints(t *testing.T) { tests.RunPostgresListStoredProcedureTest(t, ctx, pool) } +func TestAlloyDBPgPrebuiltStatementTools(t *testing.T) { + getAlloyDBPgVars(t) + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + args := []string{"--prebuilt", "alloydb-postgres"} + + cmd, cleanup, err := tests.StartCmd(ctx, map[string]any{}, args...) + if err != nil { + t.Fatalf("command initialization returned an error: %s", err) + } + defer cleanup() + + waitCtx, cancelWait := context.WithTimeout(ctx, 10*time.Second) + defer cancelWait() + 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) + } + + toolsToTest := map[string]string{ + "list_autovacuum_configurations": `{}`, + "list_memory_configurations": `{}`, + "list_top_bloated_tables": `{"limit": 10}`, + "list_replication_slots": `{}`, + "list_invalid_indexes": `{}`, + "get_query_plan": `{"query": "SELECT 1"}`, + } + + tests.RunStatementToolsTest(t, toolsToTest) +} + // Test connection with different IP type func TestAlloyDBPgIpConnection(t *testing.T) { sourceConfig := getAlloyDBPgVars(t) diff --git a/tests/tool.go b/tests/tool.go index 224e203d1647..89333cfa5beb 100644 --- a/tests/tool.go +++ b/tests/tool.go @@ -24,7 +24,6 @@ import ( "net/http" "reflect" "sort" - "strconv" "strings" "sync" "testing" @@ -1378,14 +1377,13 @@ func RunPostgresListSchemasTest(t *testing.T, ctx context.Context, pool *pgxpool wantStatusCode: http.StatusOK, want: []map[string]any{wantSchema}, }, - // TODO: Re-enable this test case after this issue is fixed: https://github.com/googleapis/genai-toolbox/issues/2562 - // { - // name: "invoke list_schemas with owner name", - // requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"owner": "%s"}`, owner))), - // wantStatusCode: http.StatusOK, - // want: []map[string]any{wantSchema}, - // compareSubset: true, - // }, + { + name: "invoke list_schemas with owner name", + requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"owner": "%s"}`, owner))), + wantStatusCode: http.StatusOK, + want: []map[string]any{wantSchema}, + compareSubset: true, + }, { name: "invoke list_schemas with limit 1", requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"schema_name": "%s","limit": 1}`, schemaName))), @@ -4418,45 +4416,8 @@ func RunPostgresListTableStatsTest(t *testing.T, ctx context.Context, pool *pgxp } } -// cleanupOldSchemas cleans up schemas that were created more than 1 hour ago -func cleanupOldSchemas(t *testing.T, ctx context.Context, pool *pgxpool.Pool) { - rows, err := pool.Query(ctx, "SELECT schema_name FROM information_schema.schemata WHERE schema_name LIKE 'test_proc_%'") - if err != nil { - return - } - defer rows.Close() - - oneHourAgo := time.Now().Add(-1 * time.Hour).Unix() - - for rows.Next() { - var name string - if err := rows.Scan(&name); err != nil { - continue - } - - parts := strings.Split(name, "_") - if len(parts) < 3 { - continue - } - - timestamp, err := strconv.ParseInt(parts[2], 10, 64) - if err != nil { - continue - } - - if timestamp < oneHourAgo { - _, err := pool.Exec(ctx, fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", name)) - if err == nil { - t.Logf("Cleaned up schema: %s", name) - } - } - } -} - // RunPostgresListStoredProcedureTest runs tests for the postgres list-stored-procedure tool func RunPostgresListStoredProcedureTest(t *testing.T, ctx context.Context, pool *pgxpool.Pool) { - cleanupOldSchemas(t, ctx, pool) - type storedProcedureDetails struct { SchemaName string `json:"schema_name"` Name string `json:"name"` @@ -4467,9 +4428,7 @@ func RunPostgresListStoredProcedureTest(t *testing.T, ctx context.Context, pool } // Create test schema - // Use this format: test_proc__ - now := time.Now().Unix() - testSchemaName := fmt.Sprintf("test_proc_%d_%s", now, strings.ReplaceAll(uuid.New().String(), "-", "")[:8]) + testSchemaName := "test_proc_schema_" + strings.ReplaceAll(uuid.New().String(), "-", "") createSchemaStmt := fmt.Sprintf("CREATE SCHEMA %s", testSchemaName) if _, err := pool.Exec(ctx, createSchemaStmt); err != nil { t.Fatalf("unable to create test schema: %v", err) @@ -4676,7 +4635,7 @@ func RunPostgresListStoredProcedureTest(t *testing.T, ctx context.Context, pool } // Verify definition contains CREATE PROCEDURE - if !strings.Contains(strings.ToUpper(proc.Definition), "PROCEDURE") { + if !strings.Contains(proc.Definition, "CREATE PROCEDURE") { t.Logf("warning: definition may not be a valid CREATE PROCEDURE statement: %s", proc.Definition) } @@ -4734,3 +4693,26 @@ func RunRequest(t *testing.T, method, url string, body io.Reader, headers map[st defer resp.Body.Close() return resp, respBody } + +func RunStatementToolsTest(t *testing.T, tools map[string]string) { + for toolName, paramBody := range tools { + t.Run(toolName, func(t *testing.T) { + api := fmt.Sprintf("http://127.0.0.1:5000/api/tool/%s/invoke", toolName) + req, err := http.NewRequest(http.MethodPost, api, bytes.NewBufferString(paramBody)) + if err != nil { + t.Fatalf("unable to create request: %s", err) + } + req.Header.Add("Content-type", "application/json") + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("unable to send request: %s", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + bodyBytes, _ := io.ReadAll(resp.Body) + t.Fatalf("response status code is not 200, got %d: %s", resp.StatusCode, string(bodyBytes)) + } + }) + } +} From 9b5b4a138571e773a4ad19dc344a40f5752ec5c2 Mon Sep 17 00:00:00 2001 From: Averi Kitsch Date: Wed, 4 Mar 2026 16:21:19 -0800 Subject: [PATCH 2/8] fix --- cmd/internal/tools_file_test.go | 9 ++- .../prebuiltconfigs/tools/alloydb-omni.yaml | 2 +- .../tools/alloydb-postgres.yaml | 2 +- tests/tool.go | 59 ++++++++++++++++--- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/cmd/internal/tools_file_test.go b/cmd/internal/tools_file_test.go index 8d30cadcd4dd..e4eb7a0ec7c8 100644 --- a/cmd/internal/tools_file_test.go +++ b/cmd/internal/tools_file_test.go @@ -1629,8 +1629,8 @@ func TestPrebuiltTools(t *testing.T) { Name: "monitor", ToolNames: []string{"database_overview", "list_active_queries", "long_running_transactions", "list_locks", "list_database_stats", "replication_stats", "list_replication_slots"}, }, - "config": tools.ToolsetConfig{ - Name: "config", + "view-config": tools.ToolsetConfig{ + Name: "view-config", ToolNames: []string{"list_columnar_configurations", "list_columnar_recommended_columns", "list_memory_configurations", "list_pg_settings", "list_available_extensions", "list_installed_extensions", "list_roles"}, }, "optimize": tools.ToolsetConfig{ @@ -1699,8 +1699,8 @@ func TestPrebuiltTools(t *testing.T) { Name: "optimize", ToolNames: []string{"list_query_stats", "list_table_stats", "get_column_cardinality", "list_top_bloated_tables", "list_invalid_indexes", "list_autovacuum_configurations"}, }, - "config": tools.ToolsetConfig{ - Name: "config", + "view-config": tools.ToolsetConfig{ + Name: "view-config", ToolNames: []string{"list_available_extensions", "list_installed_extensions", "list_pg_settings", "list_memory_configurations", "list_roles", "replication_stats", "list_replication_slots", "list_publication_tables"}, }, }, @@ -1989,7 +1989,6 @@ func TestPrebuiltTools(t *testing.T) { t.Fatalf("expected empty prompts map for prebuilt config, got: %v", toolsFile.Prompts) } - t.Run("check toolset sizes", func(t *testing.T) { for tsName, ts := range toolsFile.Toolsets { if len(ts.ToolNames) > 10 { diff --git a/internal/prebuiltconfigs/tools/alloydb-omni.yaml b/internal/prebuiltconfigs/tools/alloydb-omni.yaml index 85ffa4e96312..f8d2044e578b 100644 --- a/internal/prebuiltconfigs/tools/alloydb-omni.yaml +++ b/internal/prebuiltconfigs/tools/alloydb-omni.yaml @@ -236,7 +236,7 @@ toolsets: - list_available_extensions - list_installed_extensions - list_roles - optimize: + view-optimize: - list_query_stats - list_table_stats - get_column_cardinality diff --git a/internal/prebuiltconfigs/tools/alloydb-postgres.yaml b/internal/prebuiltconfigs/tools/alloydb-postgres.yaml index a6b4a72953f8..e0e888f88282 100644 --- a/internal/prebuiltconfigs/tools/alloydb-postgres.yaml +++ b/internal/prebuiltconfigs/tools/alloydb-postgres.yaml @@ -363,7 +363,7 @@ toolsets: - list_top_bloated_tables - list_invalid_indexes - list_autovacuum_configurations - config: + view-config: - list_available_extensions - list_installed_extensions - list_pg_settings diff --git a/tests/tool.go b/tests/tool.go index 89333cfa5beb..f73f3ec784f1 100644 --- a/tests/tool.go +++ b/tests/tool.go @@ -24,6 +24,7 @@ import ( "net/http" "reflect" "sort" + "strconv" "strings" "sync" "testing" @@ -1377,13 +1378,14 @@ func RunPostgresListSchemasTest(t *testing.T, ctx context.Context, pool *pgxpool wantStatusCode: http.StatusOK, want: []map[string]any{wantSchema}, }, - { - name: "invoke list_schemas with owner name", - requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"owner": "%s"}`, owner))), - wantStatusCode: http.StatusOK, - want: []map[string]any{wantSchema}, - compareSubset: true, - }, + // TODO: Re-enable this test case after this issue is fixed: https://github.com/googleapis/genai-toolbox/issues/2562 + // { + // name: "invoke list_schemas with owner name", + // requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"owner": "%s"}`, owner))), + // wantStatusCode: http.StatusOK, + // want: []map[string]any{wantSchema}, + // compareSubset: true, + // }, { name: "invoke list_schemas with limit 1", requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"schema_name": "%s","limit": 1}`, schemaName))), @@ -4416,8 +4418,45 @@ func RunPostgresListTableStatsTest(t *testing.T, ctx context.Context, pool *pgxp } } +// cleanupOldSchemas cleans up schemas that were created more than 1 hour ago +func cleanupOldSchemas(t *testing.T, ctx context.Context, pool *pgxpool.Pool) { + rows, err := pool.Query(ctx, "SELECT schema_name FROM information_schema.schemata WHERE schema_name LIKE 'test_proc_%'") + if err != nil { + return + } + defer rows.Close() + + oneHourAgo := time.Now().Add(-1 * time.Hour).Unix() + + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + continue + } + + parts := strings.Split(name, "_") + if len(parts) < 3 { + continue + } + + timestamp, err := strconv.ParseInt(parts[2], 10, 64) + if err != nil { + continue + } + + if timestamp < oneHourAgo { + _, err := pool.Exec(ctx, fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", name)) + if err == nil { + t.Logf("Cleaned up schema: %s", name) + } + } + } +} + // RunPostgresListStoredProcedureTest runs tests for the postgres list-stored-procedure tool func RunPostgresListStoredProcedureTest(t *testing.T, ctx context.Context, pool *pgxpool.Pool) { + cleanupOldSchemas(t, ctx, pool) + type storedProcedureDetails struct { SchemaName string `json:"schema_name"` Name string `json:"name"` @@ -4428,7 +4467,9 @@ func RunPostgresListStoredProcedureTest(t *testing.T, ctx context.Context, pool } // Create test schema - testSchemaName := "test_proc_schema_" + strings.ReplaceAll(uuid.New().String(), "-", "") + // Use this format: test_proc__ + now := time.Now().Unix() + testSchemaName := fmt.Sprintf("test_proc_%d_%s", now, strings.ReplaceAll(uuid.New().String(), "-", "")[:8]) createSchemaStmt := fmt.Sprintf("CREATE SCHEMA %s", testSchemaName) if _, err := pool.Exec(ctx, createSchemaStmt); err != nil { t.Fatalf("unable to create test schema: %v", err) @@ -4635,7 +4676,7 @@ func RunPostgresListStoredProcedureTest(t *testing.T, ctx context.Context, pool } // Verify definition contains CREATE PROCEDURE - if !strings.Contains(proc.Definition, "CREATE PROCEDURE") { + if !strings.Contains(strings.ToUpper(proc.Definition), "PROCEDURE") { t.Logf("warning: definition may not be a valid CREATE PROCEDURE statement: %s", proc.Definition) } From 4fa2dc4f72756edccc0e85ac65abfc63c0276363 Mon Sep 17 00:00:00 2001 From: Averi Kitsch Date: Wed, 4 Mar 2026 16:35:39 -0800 Subject: [PATCH 3/8] Update alloydb-omni.yaml --- internal/prebuiltconfigs/tools/alloydb-omni.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/prebuiltconfigs/tools/alloydb-omni.yaml b/internal/prebuiltconfigs/tools/alloydb-omni.yaml index f8d2044e578b..3d2dbd524dd4 100644 --- a/internal/prebuiltconfigs/tools/alloydb-omni.yaml +++ b/internal/prebuiltconfigs/tools/alloydb-omni.yaml @@ -228,7 +228,7 @@ toolsets: - list_database_stats - replication_stats - list_replication_slots - config: + view-config: - list_columnar_configurations - list_columnar_recommended_columns - list_memory_configurations @@ -236,7 +236,7 @@ toolsets: - list_available_extensions - list_installed_extensions - list_roles - view-optimize: + optimize: - list_query_stats - list_table_stats - get_column_cardinality From 322bd10296188b5f4c087a6fcf504e985bcd7565 Mon Sep 17 00:00:00 2001 From: Averi Kitsch Date: Thu, 5 Mar 2026 11:26:30 -0800 Subject: [PATCH 4/8] load in prebuilt tool env var --- .ci/integration.cloudbuild.yaml | 4 ++-- tests/alloydbpg/alloydb_pg_integration_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.ci/integration.cloudbuild.yaml b/.ci/integration.cloudbuild.yaml index 519c218301be..2dfbdb50157b 100644 --- a/.ci/integration.cloudbuild.yaml +++ b/.ci/integration.cloudbuild.yaml @@ -134,7 +134,7 @@ steps: - "ALLOYDB_POSTGRES_DATABASE=$_DATABASE_NAME" - "ALLOYDB_POSTGRES_REGION=$_REGION" - "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL" - secretEnv: ["ALLOYDB_POSTGRES_USER", "ALLOYDB_POSTGRES_PASS", "CLIENT_ID", "API_KEY"] + secretEnv: ["ALLOYDB_POSTGRES_USER", "ALLOYDB_POSTGRES_PASSWORD", "CLIENT_ID", "API_KEY"] volumes: - name: "go" path: "/gopath" @@ -1058,7 +1058,7 @@ availableSecrets: - versionName: projects/$PROJECT_ID/secrets/alloydb_pg_user/versions/latest env: ALLOYDB_POSTGRES_USER - versionName: projects/$PROJECT_ID/secrets/alloydb_pg_pass/versions/latest - env: ALLOYDB_POSTGRES_PASS + env: ALLOYDB_POSTGRES_PASSWORD - versionName: projects/$PROJECT_ID/secrets/alloydb_ai_nl_user/versions/latest env: ALLOYDB_AI_NL_USER - versionName: projects/$PROJECT_ID/secrets/alloydb_ai_nl_pass/versions/latest diff --git a/tests/alloydbpg/alloydb_pg_integration_test.go b/tests/alloydbpg/alloydb_pg_integration_test.go index 40a9c6dbdf66..388bf7a6f1d5 100644 --- a/tests/alloydbpg/alloydb_pg_integration_test.go +++ b/tests/alloydbpg/alloydb_pg_integration_test.go @@ -40,7 +40,7 @@ var ( AlloyDBPostgresInstance = os.Getenv("ALLOYDB_POSTGRES_INSTANCE") AlloyDBPostgresDatabase = os.Getenv("ALLOYDB_POSTGRES_DATABASE") AlloyDBPostgresUser = os.Getenv("ALLOYDB_POSTGRES_USER") - AlloyDBPostgresPass = os.Getenv("ALLOYDB_POSTGRES_PASS") + AlloyDBPostgresPass = os.Getenv("ALLOYDB_POSTGRES_PASSWORD") ) func getAlloyDBPgVars(t *testing.T) map[string]any { @@ -58,7 +58,7 @@ func getAlloyDBPgVars(t *testing.T) map[string]any { case AlloyDBPostgresUser: t.Fatal("'ALLOYDB_POSTGRES_USER' not set") case AlloyDBPostgresPass: - t.Fatal("'ALLOYDB_POSTGRES_PASS' not set") + t.Fatal("'ALLOYDB_POSTGRES_PASSWORD' not set") } return map[string]any{ "type": AlloyDBPostgresSourceType, From 0baae077bbf1627b9b7fe521838c79010a9efe61 Mon Sep 17 00:00:00 2001 From: Averi Kitsch Date: Wed, 11 Mar 2026 11:22:03 -0700 Subject: [PATCH 5/8] fix missing tools --- cmd/internal/tools_file_test.go | 48 +- .../prebuiltconfigs/tools/alloydb-omni.yaml | 45 +- .../tools/alloydb-postgres.yaml | 713 +++++++++--------- 3 files changed, 429 insertions(+), 377 deletions(-) diff --git a/cmd/internal/tools_file_test.go b/cmd/internal/tools_file_test.go index e4eb7a0ec7c8..e840c1316037 100644 --- a/cmd/internal/tools_file_test.go +++ b/cmd/internal/tools_file_test.go @@ -1623,19 +1623,31 @@ func TestPrebuiltTools(t *testing.T) { wantToolset: server.ToolsetConfigs{ "data": tools.ToolsetConfig{ Name: "data", - ToolNames: []string{"execute_sql", "list_tables", "list_views", "list_schemas", "get_query_plan", "list_indexes", "list_sequences", "list_stored_procedure"}, + ToolNames: []string{"execute_sql", "list_tables", "list_views", "list_schemas,", "list_triggers", "list_indexes", "list_sequences,", "list_stored_procedure"}, + }, + "performance": tools.ToolsetConfig{ + Name: "performance", + ToolNames: []string{"execute_sql", "get_query_plan", "list_query_stats", "get_column_cardinality", "list_table_stats", "list_database_stats", "list_active_queries"}, }, "monitor": tools.ToolsetConfig{ Name: "monitor", - ToolNames: []string{"database_overview", "list_active_queries", "long_running_transactions", "list_locks", "list_database_stats", "replication_stats", "list_replication_slots"}, - }, - "view-config": tools.ToolsetConfig{ - Name: "view-config", - ToolNames: []string{"list_columnar_configurations", "list_columnar_recommended_columns", "list_memory_configurations", "list_pg_settings", "list_available_extensions", "list_installed_extensions", "list_roles"}, + ToolNames: []string{"database_overview", "list_active_queries", "long_running_transactions", "list_locks", "list_database_stats", "list_pg_settings"}, }, "optimize": tools.ToolsetConfig{ Name: "optimize", - ToolNames: []string{"list_query_stats", "list_table_stats", "get_column_cardinality", "list_top_bloated_tables", "list_invalid_indexes", "list_autovacuum_configurations"}, + ToolNames: []string{"list_pg_settings", "list_memory_configurations", "list_available_extensions", "list_installed_extensions", "list_autovacuum_configurations", "list_columnar_configurations", "list_columnar_recommended_columns"}, + }, + "health": tools.ToolsetConfig{ + Name: "health", + ToolNames: []string{"list_top_bloated_tables", "list_invalid_indexes", "list_table_stats", "list_tablespaces", "database_overview", "list_autovacuum_configurations"}, + }, + "replication": tools.ToolsetConfig{ + Name: "replication", + ToolNames: []string{"replication_stats", "list_replication_slots", "list_publication_tables", "database_overview"}, + }, + "access-control": tools.ToolsetConfig{ + Name: "access-control", + ToolNames: []string{"list_roles", "list_pg_settings", "database_overview"}, }, }, }, @@ -1685,23 +1697,31 @@ func TestPrebuiltTools(t *testing.T) { wantToolset: server.ToolsetConfigs{ "admin": tools.ToolsetConfig{ Name: "admin", - ToolNames: []string{"create_cluster", "get_cluster", "list_clusters", "create_instance", "get_instance", "list_instances", "create_user", "wait_for_operation"}, + ToolNames: []string{"create_cluster", "get_cluster", "list_clusters", "create_instance", "get_instance", "list_instances", "database_overview", "wait_for_operation"}, + }, + "access-management": tools.ToolsetConfig{ + Name: "access-management", + ToolNames: []string{"create_user", "list_users", "get_user", "list_roles", "list_pg_settings", "database_overview"}, }, "data": tools.ToolsetConfig{ Name: "data", - ToolNames: []string{"execute_sql", "list_tables", "list_views", "list_schemas", "get_query_plan", "list_stored_procedure", "list_sequences", "list_indexes"}, + ToolNames: []string{"execute_sql,", "list_tables", "list_views", "list_schemas", "list_triggers,", "list_indexes", "list_sequences", "list_stored_procedure"}, }, "monitor": tools.ToolsetConfig{ Name: "monitor", - ToolNames: []string{"database_overview", "list_active_queries", "long_running_transactions", "list_locks", "get_system_metrics", "get_query_metrics", "list_database_stats"}, + ToolNames: []string{"list_active_queries", "list_query_stats", "get_query_plan", "get_query_metrics", "get_system_metrics", "long_running_transactions", "list_locks", "list_database_stats"}, + }, + "health": tools.ToolsetConfig{ + Name: "health", + ToolNames: []string{"list_top_bloated_tables", "list_invalid_indexes", "list_table_stats", "get_column_cardinality", "list_autovacuum_configurations", "list_tablespaces", "database_overview", "get_instance"}, }, "optimize": tools.ToolsetConfig{ Name: "optimize", - ToolNames: []string{"list_query_stats", "list_table_stats", "get_column_cardinality", "list_top_bloated_tables", "list_invalid_indexes", "list_autovacuum_configurations"}, + ToolNames: []string{"list_available_extensions", "list_installed_extensions", "list_memory_configurations", "list_pg_settings", "database_overview", "get_cluster"}, }, - "view-config": tools.ToolsetConfig{ - Name: "view-config", - ToolNames: []string{"list_available_extensions", "list_installed_extensions", "list_pg_settings", "list_memory_configurations", "list_roles", "replication_stats", "list_replication_slots", "list_publication_tables"}, + "replication": tools.ToolsetConfig{ + Name: "replication", + ToolNames: []string{"replication_stats", "list_replication_slots", "list_publication_tables", "list_instances", "get_instance", "database_overview"}, }, }, }, diff --git a/internal/prebuiltconfigs/tools/alloydb-omni.yaml b/internal/prebuiltconfigs/tools/alloydb-omni.yaml index 3d2dbd524dd4..b99712f808bf 100644 --- a/internal/prebuiltconfigs/tools/alloydb-omni.yaml +++ b/internal/prebuiltconfigs/tools/alloydb-omni.yaml @@ -215,31 +215,48 @@ toolsets: - execute_sql - list_tables - list_views - - list_schemas - - get_query_plan + - list_schemas, + - list_triggers - list_indexes - - list_sequences + - list_sequences, - list_stored_procedure + performance: + - execute_sql + - get_query_plan + - list_query_stats + - get_column_cardinality + - list_table_stats + - list_database_stats + - list_active_queries monitor: - database_overview - list_active_queries - long_running_transactions - list_locks - list_database_stats - - replication_stats - - list_replication_slots - view-config: - - list_columnar_configurations - - list_columnar_recommended_columns - - list_memory_configurations - list_pg_settings + optimize: + - list_pg_settings + - list_memory_configurations - list_available_extensions - list_installed_extensions - - list_roles - optimize: - - list_query_stats - - list_table_stats - - get_column_cardinality + - list_autovacuum_configurations + - list_columnar_configurations + - list_columnar_recommended_columns + health: - list_top_bloated_tables - list_invalid_indexes + - list_table_stats + - list_tablespaces + - database_overview - list_autovacuum_configurations + replication: + - replication_stats + - list_replication_slots + - list_publication_tables + - database_overview + access-control: + - list_roles + - list_pg_settings + - database_overview + diff --git a/internal/prebuiltconfigs/tools/alloydb-postgres.yaml b/internal/prebuiltconfigs/tools/alloydb-postgres.yaml index e0e888f88282..59ab839d4739 100644 --- a/internal/prebuiltconfigs/tools/alloydb-postgres.yaml +++ b/internal/prebuiltconfigs/tools/alloydb-postgres.yaml @@ -13,362 +13,377 @@ # limitations under the License. sources: - alloydb-pg-source: - kind: "alloydb-postgres" - project: ${ALLOYDB_POSTGRES_PROJECT} - region: ${ALLOYDB_POSTGRES_REGION} - cluster: ${ALLOYDB_POSTGRES_CLUSTER} - instance: ${ALLOYDB_POSTGRES_INSTANCE} - database: ${ALLOYDB_POSTGRES_DATABASE} - user: ${ALLOYDB_POSTGRES_USER:} - password: ${ALLOYDB_POSTGRES_PASSWORD:} - ipType: ${ALLOYDB_POSTGRES_IP_TYPE:public} - cloud-monitoring-source: - kind: cloud-monitoring - alloydb-admin-source: - kind: alloydb-admin - defaultProject: ${ALLOYDB_POSTGRES_PROJECT:} + alloydb-pg-source: + kind: "alloydb-postgres" + project: ${ALLOYDB_POSTGRES_PROJECT} + region: ${ALLOYDB_POSTGRES_REGION} + cluster: ${ALLOYDB_POSTGRES_CLUSTER} + instance: ${ALLOYDB_POSTGRES_INSTANCE} + database: ${ALLOYDB_POSTGRES_DATABASE} + user: ${ALLOYDB_POSTGRES_USER:} + password: ${ALLOYDB_POSTGRES_PASSWORD:} + ipType: ${ALLOYDB_POSTGRES_IP_TYPE:public} + cloud-monitoring-source: + kind: cloud-monitoring + alloydb-admin-source: + kind: alloydb-admin + defaultProject: ${ALLOYDB_POSTGRES_PROJECT:} tools: - execute_sql: - kind: postgres-execute-sql - source: alloydb-pg-source - description: Use this tool to execute sql. - list_tables: - kind: postgres-list-tables - source: alloydb-pg-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-pg-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-pg-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-pg-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-pg-source - list_locks: - kind: postgres-list-locks - source: alloydb-pg-source - replication_stats: - kind: postgres-replication-stats - source: alloydb-pg-source - list_autovacuum_configurations: - kind: postgres-sql - source: alloydb-pg-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_memory_configurations: - kind: postgres-sql - source: alloydb-pg-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-pg-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-pg-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-pg-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-pg-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-pg-source - list_schemas: - kind: postgres-list-schemas - source: alloydb-pg-source - list_indexes: - kind: postgres-list-indexes - source: alloydb-pg-source - list_sequences: - kind: postgres-list-sequences - source: alloydb-pg-source - database_overview: - kind: postgres-database-overview - source: alloydb-pg-source - list_triggers: - kind: postgres-list-triggers - source: alloydb-pg-source - list_query_stats: - kind: postgres-list-query-stats - source: alloydb-pg-source - get_column_cardinality: - kind: postgres-get-column-cardinality - source: alloydb-pg-source - list_table_stats: - kind: postgres-list-table-stats - source: alloydb-pg-source - list_publication_tables: - kind: postgres-list-publication-tables - source: alloydb-pg-source - list_tablespaces: - kind: postgres-list-tablespaces - source: alloydb-pg-source - list_pg_settings: - kind: postgres-list-pg-settings - source: alloydb-pg-source - list_database_stats: - kind: postgres-list-database-stats - source: alloydb-pg-source - list_roles: - kind: postgres-list-roles - source: alloydb-pg-source - list_stored_procedure: - kind: postgres-list-stored-procedure - source: alloydb-pg-source - get_system_metrics: - kind: cloud-monitoring-query-prometheus - source: cloud-monitoring-source - description: | - Fetches system level cloudmonitoring data (timeseries metrics) for an AlloyDB cluster, instance. - To use this tool, you must provide the Google Cloud `projectId` and a PromQL `query`. + execute_sql: + kind: postgres-execute-sql + source: alloydb-pg-source + description: Use this tool to execute sql. + list_tables: + kind: postgres-list-tables + source: alloydb-pg-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-pg-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-pg-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-pg-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-pg-source + list_locks: + kind: postgres-list-locks + source: alloydb-pg-source + replication_stats: + kind: postgres-replication-stats + source: alloydb-pg-source + list_autovacuum_configurations: + kind: postgres-sql + source: alloydb-pg-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_memory_configurations: + kind: postgres-sql + source: alloydb-pg-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-pg-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-pg-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-pg-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-pg-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-pg-source + list_schemas: + kind: postgres-list-schemas + source: alloydb-pg-source + list_indexes: + kind: postgres-list-indexes + source: alloydb-pg-source + list_sequences: + kind: postgres-list-sequences + source: alloydb-pg-source + database_overview: + kind: postgres-database-overview + source: alloydb-pg-source + list_triggers: + kind: postgres-list-triggers + source: alloydb-pg-source + list_query_stats: + kind: postgres-list-query-stats + source: alloydb-pg-source + get_column_cardinality: + kind: postgres-get-column-cardinality + source: alloydb-pg-source + list_table_stats: + kind: postgres-list-table-stats + source: alloydb-pg-source + list_publication_tables: + kind: postgres-list-publication-tables + source: alloydb-pg-source + list_tablespaces: + kind: postgres-list-tablespaces + source: alloydb-pg-source + list_pg_settings: + kind: postgres-list-pg-settings + source: alloydb-pg-source + list_database_stats: + kind: postgres-list-database-stats + source: alloydb-pg-source + list_roles: + kind: postgres-list-roles + source: alloydb-pg-source + list_stored_procedure: + kind: postgres-list-stored-procedure + source: alloydb-pg-source + get_system_metrics: + kind: cloud-monitoring-query-prometheus + source: cloud-monitoring-source + description: | + Fetches system level cloudmonitoring data (timeseries metrics) for an AlloyDB cluster, instance. + To use this tool, you must provide the Google Cloud `projectId` and a PromQL `query`. - Generate the PromQL `query` for AlloyDB system metrics using the provided metrics and rules. Get labels like `cluster_id` and `instance_id` from the user's intent. + Generate the PromQL `query` for AlloyDB system metrics using the provided metrics and rules. Get labels like `cluster_id` and `instance_id` from the user's intent. - Defaults: - 1. Interval: Use a default interval of `5m` for `_over_time` aggregation functions unless a different window is specified by the user. + Defaults: + 1. Interval: Use a default interval of `5m` for `_over_time` aggregation functions unless a different window is specified by the user. - PromQL Query Examples: - 1. Basic Time Series: `avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance"}[5m])` - 2. Top K: `topk(30, avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance"}[5m]))` - 3. Mean: `avg(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="my-instance","cluster_id"="my-cluster"}[5m]))` - 4. Minimum: `min(min_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` - 5. Maximum: `max(max_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` - 6. Sum: `sum(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` - 7. Count streams: `count(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` - 8. Percentile with groupby on instanceid, clusterid: `quantile by ("instance_id","cluster_id")(0.99,avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","cluster_id"="my-cluster","instance_id"="my-instance"}[5m]))` + PromQL Query Examples: + 1. Basic Time Series: `avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance"}[5m])` + 2. Top K: `topk(30, avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance"}[5m]))` + 3. Mean: `avg(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="my-instance","cluster_id"="my-cluster"}[5m]))` + 4. Minimum: `min(min_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 5. Maximum: `max(max_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 6. Sum: `sum(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 7. Count streams: `count(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 8. Percentile with groupby on instanceid, clusterid: `quantile by ("instance_id","cluster_id")(0.99,avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","cluster_id"="my-cluster","instance_id"="my-instance"}[5m]))` - Available Metrics List: metricname. description. monitored resource. labels - 1. `alloydb.googleapis.com/instance/cpu/average_utilization`: The percentage of CPU being used on an instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 2. `alloydb.googleapis.com/instance/cpu/maximum_utilization`: Maximum CPU utilization across all currently serving nodes of the instance from 0 to 100. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 3. `alloydb.googleapis.com/cluster/storage/usage`: The total AlloyDB storage in bytes across the entire cluster. `alloydb.googleapis.com/Cluster`. `cluster_id`. - 4. `alloydb.googleapis.com/instance/postgres/replication/replicas`: The number of read replicas connected to the primary instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `state`, `replica_instance_id`. - 5. `alloydb.googleapis.com/instance/postgres/replication/maximum_lag`: The maximum replication time lag calculated across all serving read replicas of the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `replica_instance_id`. - 6. `alloydb.googleapis.com/instance/memory/min_available_memory`: The minimum available memory across all currently serving nodes of the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 7. `alloydb.googleapis.com/instance/postgres/instances`: The number of nodes in the instance, along with their status, which can be either up or down. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `status`. - 8. `alloydb.googleapis.com/database/postgresql/tuples`: Number of tuples (rows) by state per database in the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`, `state`. - 9. `alloydb.googleapis.com/database/postgresql/temp_bytes_written_for_top_databases`: The total amount of data(in bytes) written to temporary files by the queries per database for top 500 dbs. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. - 10. `alloydb.googleapis.com/database/postgresql/temp_files_written_for_top_databases`: The number of temporary files used for writing data per database while performing internal algorithms like join, sort etc for top 500 dbs. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. - 11. `alloydb.googleapis.com/database/postgresql/inserted_tuples_count_for_top_databases`: The total number of rows inserted per db for top 500 dbs as a result of the queries in the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. - 12. `alloydb.googleapis.com/database/postgresql/updated_tuples_count_for_top_databases`: The total number of rows updated per db for top 500 dbs as a result of the queries in the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. - 13. `alloydb.googleapis.com/database/postgresql/deleted_tuples_count_for_top_databases`: The total number of rows deleted per db for top 500 dbs as a result of the queries in the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. - 14. `alloydb.googleapis.com/database/postgresql/backends_for_top_databases`: The current number of connections per database to the instance for top 500 dbs. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. - 15. `alloydb.googleapis.com/instance/postgresql/backends_by_state`: The current number of connections to the instance grouped by the state like idle, active, idle_in_transaction, idle_in_transaction_aborted, disabled, and fastpath_function_call. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `state`. - 16. `alloydb.googleapis.com/instance/postgresql/backends_for_top_applications`: The current number of connections to the AlloyDB instance, grouped by applications for top 500 applications. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `application_name`. - 17. `alloydb.googleapis.com/database/postgresql/new_connections_for_top_databases`: Total number of new connections added per database for top 500 databases to the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. - 18. `alloydb.googleapis.com/database/postgresql/deadlock_count_for_top_databases`: Total number of deadlocks detected in the instance per database for top 500 dbs. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. - 19. `alloydb.googleapis.com/database/postgresql/statements_executed_count`: Total count of statements executed in the instance per database per operation_type. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`, `operation_type`. - 20. `alloydb.googleapis.com/instance/postgresql/returned_tuples_count`: Number of rows scanned while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 21. `alloydb.googleapis.com/instance/postgresql/fetched_tuples_count`: Number of rows fetched while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 22. `alloydb.googleapis.com/instance/postgresql/updated_tuples_count`: Number of rows updated while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 23. `alloydb.googleapis.com/instance/postgresql/inserted_tuples_count`: Number of rows inserted while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 24. `alloydb.googleapis.com/instance/postgresql/deleted_tuples_count`: Number of rows deleted while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 25. `alloydb.googleapis.com/instance/postgresql/written_tuples_count`: Number of rows written while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 26. `alloydb.googleapis.com/instance/postgresql/deadlock_count`: Number of deadlocks detected in the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 27. `alloydb.googleapis.com/instance/postgresql/blks_read`: Number of blocks read by Postgres that were not in the buffer cache. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 28. `alloydb.googleapis.com/instance/postgresql/blks_hit`: Number of times Postgres found the requested block in the buffer cache. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 29. `alloydb.googleapis.com/instance/postgresql/temp_bytes_written_count`: The total amount of data(in bytes) written to temporary files by the queries while performing internal algorithms like join, sort etc. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 30. `alloydb.googleapis.com/instance/postgresql/temp_files_written_count`: The number of temporary files used for writing data in the instance while performing internal algorithms like join, sort etc. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 31. `alloydb.googleapis.com/instance/postgresql/new_connections_count`: The number new connections added to the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - 32. `alloydb.googleapis.com/instance/postgresql/wait_count`: Total number of times processes waited for each wait event in the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `wait_event_type`, `wait_event_name`. - 33. `alloydb.googleapis.com/instance/postgresql/wait_time`: Total elapsed wait time for each wait event in the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `wait_event_type`, `wait_event_name`. - 34. `alloydb.googleapis.com/instance/postgres/transaction_count`: The number of committed and rolled back transactions across all serving nodes of the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. - list_clusters: - kind: alloydb-list-clusters - source: alloydb-admin-source - create_cluster: - kind: alloydb-create-cluster - source: alloydb-admin-source - create_user: - kind: alloydb-create-user - source: alloydb-admin-source - wait_for_operation: - kind: alloydb-wait-for-operation - source: alloydb-admin-source - delay: 1s - maxDelay: 4m - multiplier: 2 - maxRetries: 10 - get_query_metrics: - kind: cloud-monitoring-query-prometheus - source: cloud-monitoring-source - description: | - Fetches query level cloudmonitoring data (timeseries metrics) for queries running in an AlloyDB instance. - To use this tool, you must provide the Google Cloud `projectId` and a PromQL `query`. + Available Metrics List: metricname. description. monitored resource. labels + 1. `alloydb.googleapis.com/instance/cpu/average_utilization`: The percentage of CPU being used on an instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 2. `alloydb.googleapis.com/instance/cpu/maximum_utilization`: Maximum CPU utilization across all currently serving nodes of the instance from 0 to 100. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 3. `alloydb.googleapis.com/cluster/storage/usage`: The total AlloyDB storage in bytes across the entire cluster. `alloydb.googleapis.com/Cluster`. `cluster_id`. + 4. `alloydb.googleapis.com/instance/postgres/replication/replicas`: The number of read replicas connected to the primary instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `state`, `replica_instance_id`. + 5. `alloydb.googleapis.com/instance/postgres/replication/maximum_lag`: The maximum replication time lag calculated across all serving read replicas of the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `replica_instance_id`. + 6. `alloydb.googleapis.com/instance/memory/min_available_memory`: The minimum available memory across all currently serving nodes of the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 7. `alloydb.googleapis.com/instance/postgres/instances`: The number of nodes in the instance, along with their status, which can be either up or down. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `status`. + 8. `alloydb.googleapis.com/database/postgresql/tuples`: Number of tuples (rows) by state per database in the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`, `state`. + 9. `alloydb.googleapis.com/database/postgresql/temp_bytes_written_for_top_databases`: The total amount of data(in bytes) written to temporary files by the queries per database for top 500 dbs. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 10. `alloydb.googleapis.com/database/postgresql/temp_files_written_for_top_databases`: The number of temporary files used for writing data per database while performing internal algorithms like join, sort etc for top 500 dbs. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 11. `alloydb.googleapis.com/database/postgresql/inserted_tuples_count_for_top_databases`: The total number of rows inserted per db for top 500 dbs as a result of the queries in the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 12. `alloydb.googleapis.com/database/postgresql/updated_tuples_count_for_top_databases`: The total number of rows updated per db for top 500 dbs as a result of the queries in the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 13. `alloydb.googleapis.com/database/postgresql/deleted_tuples_count_for_top_databases`: The total number of rows deleted per db for top 500 dbs as a result of the queries in the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 14. `alloydb.googleapis.com/database/postgresql/backends_for_top_databases`: The current number of connections per database to the instance for top 500 dbs. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 15. `alloydb.googleapis.com/instance/postgresql/backends_by_state`: The current number of connections to the instance grouped by the state like idle, active, idle_in_transaction, idle_in_transaction_aborted, disabled, and fastpath_function_call. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `state`. + 16. `alloydb.googleapis.com/instance/postgresql/backends_for_top_applications`: The current number of connections to the AlloyDB instance, grouped by applications for top 500 applications. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `application_name`. + 17. `alloydb.googleapis.com/database/postgresql/new_connections_for_top_databases`: Total number of new connections added per database for top 500 databases to the instance. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 18. `alloydb.googleapis.com/database/postgresql/deadlock_count_for_top_databases`: Total number of deadlocks detected in the instance per database for top 500 dbs. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`. + 19. `alloydb.googleapis.com/database/postgresql/statements_executed_count`: Total count of statements executed in the instance per database per operation_type. `alloydb.googleapis.com/Database`. `cluster_id`, `instance_id`, `database`, `operation_type`. + 20. `alloydb.googleapis.com/instance/postgresql/returned_tuples_count`: Number of rows scanned while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 21. `alloydb.googleapis.com/instance/postgresql/fetched_tuples_count`: Number of rows fetched while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 22. `alloydb.googleapis.com/instance/postgresql/updated_tuples_count`: Number of rows updated while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 23. `alloydb.googleapis.com/instance/postgresql/inserted_tuples_count`: Number of rows inserted while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 24. `alloydb.googleapis.com/instance/postgresql/deleted_tuples_count`: Number of rows deleted while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 25. `alloydb.googleapis.com/instance/postgresql/written_tuples_count`: Number of rows written while processing the queries in the instance since the last sample. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 26. `alloydb.googleapis.com/instance/postgresql/deadlock_count`: Number of deadlocks detected in the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 27. `alloydb.googleapis.com/instance/postgresql/blks_read`: Number of blocks read by Postgres that were not in the buffer cache. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 28. `alloydb.googleapis.com/instance/postgresql/blks_hit`: Number of times Postgres found the requested block in the buffer cache. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 29. `alloydb.googleapis.com/instance/postgresql/temp_bytes_written_count`: The total amount of data(in bytes) written to temporary files by the queries while performing internal algorithms like join, sort etc. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 30. `alloydb.googleapis.com/instance/postgresql/temp_files_written_count`: The number of temporary files used for writing data in the instance while performing internal algorithms like join, sort etc. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 31. `alloydb.googleapis.com/instance/postgresql/new_connections_count`: The number new connections added to the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + 32. `alloydb.googleapis.com/instance/postgresql/wait_count`: Total number of times processes waited for each wait event in the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `wait_event_type`, `wait_event_name`. + 33. `alloydb.googleapis.com/instance/postgresql/wait_time`: Total elapsed wait time for each wait event in the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`, `wait_event_type`, `wait_event_name`. + 34. `alloydb.googleapis.com/instance/postgres/transaction_count`: The number of committed and rolled back transactions across all serving nodes of the instance. `alloydb.googleapis.com/Instance`. `cluster_id`, `instance_id`. + list_clusters: + kind: alloydb-list-clusters + source: alloydb-admin-source + create_cluster: + kind: alloydb-create-cluster + source: alloydb-admin-source + create_user: + kind: alloydb-create-user + source: alloydb-admin-source + wait_for_operation: + kind: alloydb-wait-for-operation + source: alloydb-admin-source + delay: 1s + maxDelay: 4m + multiplier: 2 + maxRetries: 10 + get_query_metrics: + kind: cloud-monitoring-query-prometheus + source: cloud-monitoring-source + description: | + Fetches query level cloudmonitoring data (timeseries metrics) for queries running in an AlloyDB instance. + To use this tool, you must provide the Google Cloud `projectId` and a PromQL `query`. - Generate the PromQL `query` for AlloyDB query metrics using the provided metrics and rules. Get labels like `cluster_id`, `instance_id`, and `query_hash` from the user's intent. If `query_hash` is provided, use the per-query metrics. + Generate the PromQL `query` for AlloyDB query metrics using the provided metrics and rules. Get labels like `cluster_id`, `instance_id`, and `query_hash` from the user's intent. If `query_hash` is provided, use the per-query metrics. - Defaults: - 1. Interval: Use a default interval of `5m` for `_over_time` aggregation functions unless a different window is specified by the user. + Defaults: + 1. Interval: Use a default interval of `5m` for `_over_time` aggregation functions unless a different window is specified by the user. - PromQL Query Examples: - 1. Basic Time Series: `avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance"}[5m])` - 2. Top K: `topk(30, avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance"}[5m]))` - 3. Mean: `avg(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="my-instance","cluster_id"="my-cluster"}[5m]))` - 4. Minimum: `min(min_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` - 5. Maximum: `max(max_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` - 6. Sum: `sum(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` - 7. Count streams: `count(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` - 8. Percentile with groupby on instanceid, clusterid: `quantile by ("instance_id","cluster_id")(0.99,avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","cluster_id"="my-cluster","instance_id"="my-instance"}[5m]))` + PromQL Query Examples: + 1. Basic Time Series: `avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance"}[5m])` + 2. Top K: `topk(30, avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance"}[5m]))` + 3. Mean: `avg(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="my-instance","cluster_id"="my-cluster"}[5m]))` + 4. Minimum: `min(min_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 5. Maximum: `max(max_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 6. Sum: `sum(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 7. Count streams: `count(avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","instance_id"="alloydb-instance","cluster_id"="alloydb-cluster"}[5m]))` + 8. Percentile with groupby on instanceid, clusterid: `quantile by ("instance_id","cluster_id")(0.99,avg_over_time({"__name__"="alloydb.googleapis.com/instance/cpu/average_utilization","monitored_resource"="alloydb.googleapis.com/Instance","cluster_id"="my-cluster","instance_id"="my-instance"}[5m]))` - Available Metrics List: metricname. description. monitored resource. labels. aggregate is the aggregated values for all query stats, Use aggregate metrics if query id is not provided. For perquery metrics do not fetch querystring unless specified by user specifically. Have the aggregation on query hash to avoid fetching the querystring. Do not use latency metrics for anything. - 1. `alloydb.googleapis.com/database/postgresql/insights/aggregate/latencies`: Aggregated query latency distribution. `alloydb.googleapis.com/Database`. `user`, `client_addr`. - 2. `alloydb.googleapis.com/database/postgresql/insights/aggregate/execution_time`: Accumulated aggregated query execution time since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`. - 3. `alloydb.googleapis.com/database/postgresql/insights/aggregate/io_time`: Accumulated aggregated IO time since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `io_type`. - 4. `alloydb.googleapis.com/database/postgresql/insights/aggregate/lock_time`: Accumulated aggregated lock wait time since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `lock_type`. - 5. `alloydb.googleapis.com/database/postgresql/insights/aggregate/row_count`: Aggregated number of retrieved or affected rows since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`. - 6. `alloydb.googleapis.com/database/postgresql/insights/aggregate/shared_blk_access_count`: Aggregated shared blocks accessed by statement execution. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `access_type`. - 7. `alloydb.googleapis.com/database/postgresql/insights/perquery/latencies`: Per query latency distribution. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `querystring`, `query_hash`. - 8. `alloydb.googleapis.com/database/postgresql/insights/perquery/execution_time`: Accumulated execution times per user per database per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `querystring`, `query_hash`. - 9. `alloydb.googleapis.com/database/postgresql/insights/perquery/io_time`: Accumulated IO time since the last sample per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `io_type`, `querystring`, `query_hash`. - 10. `alloydb.googleapis.com/database/postgresql/insights/perquery/lock_time`: Accumulated lock wait time since the last sample per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `lock_type`, `querystring`, `query_hash`. - 11. `alloydb.googleapis.com/database/postgresql/insights/perquery/row_count`: The number of retrieved or affected rows since the last sample per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `querystring`, `query_hash`. - 12. `alloydb.googleapis.com/database/postgresql/insights/perquery/shared_blk_access_count`: Shared blocks accessed by statement execution per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `access_type`, `querystring`, `query_hash`. - 13. `alloydb.googleapis.com/database/postgresql/insights/pertag/latencies`: Query latency distribution. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`. - 14. `alloydb.googleapis.com/database/postgresql/insights/pertag/execution_time`: Accumulated execution times since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`. - 15. `alloydb.googleapis.com/database/postgresql/insights/pertag/io_time`: Accumulated IO time since the last sample per tag. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `io_type`, `tag_hash`. - 16. `alloydb.googleapis.com/database/postgresql/insights/pertag/lock_time`: Accumulated lock wait time since the last sample per tag. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `lock_type`, `tag_hash`. - 17. `alloydb.googleapis.com/database/postgresql/insights/pertag/shared_blk_access_count`: Shared blocks accessed by statement execution per tag. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `access_type`, `tag_hash`. - 18. `alloydb.googleapis.com/database/postgresql/insights/pertag/row_count`: The number of retrieved or affected rows since the last sample per tag. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`. - get_instance: - kind: alloydb-get-instance - source: alloydb-admin-source - get_cluster: - kind: alloydb-get-cluster - source: alloydb-admin-source - create_instance: - kind: alloydb-create-instance - source: alloydb-admin-source - list_instances: - kind: alloydb-list-instances - source: alloydb-admin-source + Available Metrics List: metricname. description. monitored resource. labels. aggregate is the aggregated values for all query stats, Use aggregate metrics if query id is not provided. For perquery metrics do not fetch querystring unless specified by user specifically. Have the aggregation on query hash to avoid fetching the querystring. Do not use latency metrics for anything. + 1. `alloydb.googleapis.com/database/postgresql/insights/aggregate/latencies`: Aggregated query latency distribution. `alloydb.googleapis.com/Database`. `user`, `client_addr`. + 2. `alloydb.googleapis.com/database/postgresql/insights/aggregate/execution_time`: Accumulated aggregated query execution time since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`. + 3. `alloydb.googleapis.com/database/postgresql/insights/aggregate/io_time`: Accumulated aggregated IO time since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `io_type`. + 4. `alloydb.googleapis.com/database/postgresql/insights/aggregate/lock_time`: Accumulated aggregated lock wait time since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `lock_type`. + 5. `alloydb.googleapis.com/database/postgresql/insights/aggregate/row_count`: Aggregated number of retrieved or affected rows since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`. + 6. `alloydb.googleapis.com/database/postgresql/insights/aggregate/shared_blk_access_count`: Aggregated shared blocks accessed by statement execution. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `access_type`. + 7. `alloydb.googleapis.com/database/postgresql/insights/perquery/latencies`: Per query latency distribution. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `querystring`, `query_hash`. + 8. `alloydb.googleapis.com/database/postgresql/insights/perquery/execution_time`: Accumulated execution times per user per database per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `querystring`, `query_hash`. + 9. `alloydb.googleapis.com/database/postgresql/insights/perquery/io_time`: Accumulated IO time since the last sample per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `io_type`, `querystring`, `query_hash`. + 10. `alloydb.googleapis.com/database/postgresql/insights/perquery/lock_time`: Accumulated lock wait time since the last sample per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `lock_type`, `querystring`, `query_hash`. + 11. `alloydb.googleapis.com/database/postgresql/insights/perquery/row_count`: The number of retrieved or affected rows since the last sample per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `querystring`, `query_hash`. + 12. `alloydb.googleapis.com/database/postgresql/insights/perquery/shared_blk_access_count`: Shared blocks accessed by statement execution per query. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `access_type`, `querystring`, `query_hash`. + 13. `alloydb.googleapis.com/database/postgresql/insights/pertag/latencies`: Query latency distribution. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`. + 14. `alloydb.googleapis.com/database/postgresql/insights/pertag/execution_time`: Accumulated execution times since the last sample. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`. + 15. `alloydb.googleapis.com/database/postgresql/insights/pertag/io_time`: Accumulated IO time since the last sample per tag. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `io_type`, `tag_hash`. + 16. `alloydb.googleapis.com/database/postgresql/insights/pertag/lock_time`: Accumulated lock wait time since the last sample per tag. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `lock_type`, `tag_hash`. + 17. `alloydb.googleapis.com/database/postgresql/insights/pertag/shared_blk_access_count`: Shared blocks accessed by statement execution per tag. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `access_type`, `tag_hash`. + 18. `alloydb.googleapis.com/database/postgresql/insights/pertag/row_count`: The number of retrieved or affected rows since the last sample per tag. `alloydb.googleapis.com/Database`. `user`, `client_addr`, `action`, `application`, `controller`, `db_driver`, `framework`, `route`, `tag_hash`. + get_instance: + kind: alloydb-get-instance + source: alloydb-admin-source + get_cluster: + kind: alloydb-get-cluster + source: alloydb-admin-source + create_instance: + kind: alloydb-create-instance + source: alloydb-admin-source + list_instances: + kind: alloydb-list-instances + source: alloydb-admin-source toolsets: - admin: - - create_cluster - - get_cluster - - list_clusters - - create_instance - - get_instance - - list_instances - - create_user - - wait_for_operation - data: - - execute_sql - - list_tables - - list_views - - list_schemas - - get_query_plan - - list_stored_procedure - - list_sequences - - list_indexes - monitor: - - database_overview - - list_active_queries - - long_running_transactions - - list_locks - - get_system_metrics - - get_query_metrics - - list_database_stats - optimize: - - list_query_stats - - list_table_stats - - get_column_cardinality - - list_top_bloated_tables - - list_invalid_indexes - - list_autovacuum_configurations - view-config: - - list_available_extensions - - list_installed_extensions - - list_pg_settings - - list_memory_configurations - - list_roles - - replication_stats - - list_replication_slots - - list_publication_tables + admin: + - create_cluster + - get_cluster + - list_clusters + - create_instance + - get_instance + - list_instances + - database_overview + - wait_for_operation + access-management: + - create_user + - list_users + - get_user + - list_roles + - list_pg_settings + - database_overview + data: + - execute_sql, + - list_tables + - list_views + - list_schemas + - list_triggers, + - list_indexes + - list_sequences + - list_stored_procedure + monitor: + - list_active_queries + - list_query_stats + - get_query_plan + - get_query_metrics + - get_system_metrics + - long_running_transactions + - list_locks + - list_database_stats + health: + - list_top_bloated_tables + - list_invalid_indexes + - list_table_stats + - get_column_cardinality + - list_autovacuum_configurations + - list_tablespaces + - database_overview + - get_instance + optimize: + - list_available_extensions + - list_installed_extensions + - list_memory_configurations + - list_pg_settings + - database_overview + - get_cluster + replication: + - replication_stats + - list_replication_slots + - list_publication_tables + - list_instances + - get_instance + - database_overview From 9ac76b2017012ad151fa4dd4c003b07830d0063d Mon Sep 17 00:00:00 2001 From: Averi Kitsch Date: Wed, 11 Mar 2026 11:37:28 -0700 Subject: [PATCH 6/8] fix typos --- cmd/internal/tools_file_test.go | 5 +- .../prebuiltconfigs/tools/alloydb-omni.yaml | 489 +++++++++--------- .../tools/alloydb-postgres.yaml | 4 +- 3 files changed, 248 insertions(+), 250 deletions(-) diff --git a/cmd/internal/tools_file_test.go b/cmd/internal/tools_file_test.go index e840c1316037..c451cf536aa8 100644 --- a/cmd/internal/tools_file_test.go +++ b/cmd/internal/tools_file_test.go @@ -1623,7 +1623,7 @@ func TestPrebuiltTools(t *testing.T) { wantToolset: server.ToolsetConfigs{ "data": tools.ToolsetConfig{ Name: "data", - ToolNames: []string{"execute_sql", "list_tables", "list_views", "list_schemas,", "list_triggers", "list_indexes", "list_sequences,", "list_stored_procedure"}, + ToolNames: []string{"execute_sql", "list_tables", "list_views", "list_schemas", "list_triggers", "list_indexes", "list_sequences", "list_stored_procedure"}, }, "performance": tools.ToolsetConfig{ Name: "performance", @@ -1705,7 +1705,7 @@ func TestPrebuiltTools(t *testing.T) { }, "data": tools.ToolsetConfig{ Name: "data", - ToolNames: []string{"execute_sql,", "list_tables", "list_views", "list_schemas", "list_triggers,", "list_indexes", "list_sequences", "list_stored_procedure"}, + ToolNames: []string{"execute_sql", "list_tables", "list_views", "list_schemas", "list_triggers", "list_indexes", "list_sequences", "list_stored_procedure"}, }, "monitor": tools.ToolsetConfig{ Name: "monitor", @@ -2013,7 +2013,6 @@ func TestPrebuiltTools(t *testing.T) { for tsName, ts := range toolsFile.Toolsets { if len(ts.ToolNames) > 10 { t.Logf("WARNING: Toolset %q in config %q has %d tools, which is larger than the recommended maximum of 10.", tsName, tc.name, len(ts.ToolNames)) - fmt.Printf("WARNING: Toolset %q in config %q has %d tools, which is larger than the recommended maximum of 10.\n", tsName, tc.name, len(ts.ToolNames)) } } }) diff --git a/internal/prebuiltconfigs/tools/alloydb-omni.yaml b/internal/prebuiltconfigs/tools/alloydb-omni.yaml index b99712f808bf..0d3837b08879 100644 --- a/internal/prebuiltconfigs/tools/alloydb-omni.yaml +++ b/internal/prebuiltconfigs/tools/alloydb-omni.yaml @@ -13,250 +13,249 @@ # 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:} + 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 + 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: - data: - - execute_sql - - list_tables - - list_views - - list_schemas, - - list_triggers - - list_indexes - - list_sequences, - - list_stored_procedure - performance: - - execute_sql - - get_query_plan - - list_query_stats - - get_column_cardinality - - list_table_stats - - list_database_stats - - list_active_queries - monitor: - - database_overview - - list_active_queries - - long_running_transactions - - list_locks - - list_database_stats - - list_pg_settings - optimize: - - list_pg_settings - - list_memory_configurations - - list_available_extensions - - list_installed_extensions - - list_autovacuum_configurations - - list_columnar_configurations - - list_columnar_recommended_columns - health: - - list_top_bloated_tables - - list_invalid_indexes - - list_table_stats - - list_tablespaces - - database_overview - - list_autovacuum_configurations - replication: - - replication_stats - - list_replication_slots - - list_publication_tables - - database_overview - access-control: - - list_roles - - list_pg_settings - - database_overview - + data: + - execute_sql + - list_tables + - list_views + - list_schemas + - list_triggers + - list_indexes + - list_sequences + - list_stored_procedure + performance: + - execute_sql + - get_query_plan + - list_query_stats + - get_column_cardinality + - list_table_stats + - list_database_stats + - list_active_queries + monitor: + - database_overview + - list_active_queries + - long_running_transactions + - list_locks + - list_database_stats + - list_pg_settings + optimize: + - list_pg_settings + - list_memory_configurations + - list_available_extensions + - list_installed_extensions + - list_autovacuum_configurations + - list_columnar_configurations + - list_columnar_recommended_columns + health: + - list_top_bloated_tables + - list_invalid_indexes + - list_table_stats + - list_tablespaces + - database_overview + - list_autovacuum_configurations + replication: + - replication_stats + - list_replication_slots + - list_publication_tables + - database_overview + access-control: + - list_roles + - list_pg_settings + - database_overview diff --git a/internal/prebuiltconfigs/tools/alloydb-postgres.yaml b/internal/prebuiltconfigs/tools/alloydb-postgres.yaml index 59ab839d4739..99559527ab27 100644 --- a/internal/prebuiltconfigs/tools/alloydb-postgres.yaml +++ b/internal/prebuiltconfigs/tools/alloydb-postgres.yaml @@ -347,11 +347,11 @@ toolsets: - list_pg_settings - database_overview data: - - execute_sql, + - execute_sql - list_tables - list_views - list_schemas - - list_triggers, + - list_triggers - list_indexes - list_sequences - list_stored_procedure From 71767084a0f0b597581dae1c3dbb19d193ea5a99 Mon Sep 17 00:00:00 2001 From: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> Date: Fri, 13 Mar 2026 10:16:02 -0700 Subject: [PATCH 7/8] Update alloydb-postgres.yaml --- internal/prebuiltconfigs/tools/alloydb-postgres.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/prebuiltconfigs/tools/alloydb-postgres.yaml b/internal/prebuiltconfigs/tools/alloydb-postgres.yaml index 99559527ab27..8380bf923e52 100644 --- a/internal/prebuiltconfigs/tools/alloydb-postgres.yaml +++ b/internal/prebuiltconfigs/tools/alloydb-postgres.yaml @@ -266,6 +266,9 @@ tools: create_cluster: kind: alloydb-create-cluster source: alloydb-admin-source + list_users: + kind: alloydb-list-users + source: alloydb-admin-source create_user: kind: alloydb-create-user source: alloydb-admin-source From 910fd34e12e43a08a7277182556a39ace55eaba8 Mon Sep 17 00:00:00 2001 From: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> Date: Fri, 13 Mar 2026 10:27:47 -0700 Subject: [PATCH 8/8] Update alloydb-postgres.yaml --- internal/prebuiltconfigs/tools/alloydb-postgres.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/prebuiltconfigs/tools/alloydb-postgres.yaml b/internal/prebuiltconfigs/tools/alloydb-postgres.yaml index 8380bf923e52..3125a719fa78 100644 --- a/internal/prebuiltconfigs/tools/alloydb-postgres.yaml +++ b/internal/prebuiltconfigs/tools/alloydb-postgres.yaml @@ -272,6 +272,9 @@ tools: create_user: kind: alloydb-create-user source: alloydb-admin-source + get_user: + kind: alloydb-get-user + source: alloydb-admin-source wait_for_operation: kind: alloydb-wait-for-operation source: alloydb-admin-source